Railway Operation Simulator  v2.9.2
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <Clipbrd.hpp> //for selection clipboard functions at v2.8.0
38 #include <fstream>
39 #include <sstream> //for clipboard functions at v2.8.0
40 #include <vector>
41 #include <vcl.h>
42 #include <stdio.h>
43 #include <algorithm> //for sort
44 
45 #pragma hdrstop
46 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
47 // They aren't all needed in each case but being together and identical they speed
48 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
49 // conjunction with 'use pre-compiled headers' in the project compiler options.
50 
51 #include "InterfaceUnit.h"
52 #include "GraphicUnit.h"
53 #include "DisplayUnit.h"
54 #include "TextUnit.h"
55 #include "TrainUnit.h"
56 #include "Utilities.h"
57 #include "TrackUnit.h"
58 #include "AboutUnit.h"
59 #include <fstream>
60 #include <dirent.h>
61 #include <Filectrl.hpp> //to check whether directories exist
62 
63 // ---------------------------------------------------------------------------
64 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
65 #pragma package(smart_init)
66 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
67 #pragma resource "*.dfm"
68 
70 
71 // Folder Names
72 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
73 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
74 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
75 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
76 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
77 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
78 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
79 
80 // ---------------------------------------------------------------------------
81 
82 __fastcall TInterface::TInterface(TComponent* Owner) : TForm(Owner)
83 {
84  // constructor
85  try
86  {
87  Screen->Cursor = TCursor(-11); // Hourglass
88  DirOpenError = false;
89  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
90  // initial setup
91  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
92  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
94  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
95  // development stages (don't show on published versions)
96 
97  // check for presence of directories, creation failure probably indicates that the
98  // working folder is read-only
99 
100  CurDir = AnsiString(GetCurrentDir());
101 // ShowMessage("Curdir from GetCurrentDir() " + CurDir); //these used to check behaviour outside the compiler
102  UnicodeString FullProgramName = GetModuleName(0); // added at v2.9.0 to check executable exists
103 // ShowMessage("FullProgramName " + FullProgramName);
104  UnicodeString ProgramName = ExtractFileName(FullProgramName); // as above
105 // ShowMessage("ProgramName " + ProgramName);
106  UnicodeString ProgramDirectoryName = ExtractFilePath(FullProgramName); // as above
107 // ShowMessage("ProgramDirectoryName " + ProgramDirectoryName);
108 
109  if(!FileExists(ProgramName)) //added at v2.9.0 after discovering the effect described below
110  {
111  if(!SetCurrentDir(ProgramDirectoryName)) //if false the current directory couldn't be changed
112  {
113  ShowMessage("The working directory does not contain the railway executable file so the program cannot "
114  "open. This is usually because the program has been selected via the right-click taskbar icon though it may "
115  "also happen in other circumstances. It is caused by the Windows operating system re-assigning the "
116  "working directory for some unknown reason, though whether or not it happens appears to depend on the "
117  "Windows update version.\n\n"
118  "To avoid this happening please open the program by double clicking the program icon on the desktop "
119  "if there is one, or the program icon shown in Windows Explorer.");
120  Application->Terminate();
121  }
122  else
123  {
124  CurDir = AnsiString(GetCurrentDir());
125  }
126  }
127 
128  if(!DirectoryExists(RAILWAY_DIR_NAME))
129  {
130  if(!CreateDir(RAILWAY_DIR_NAME))
131  {
132  DirOpenError = true;
133  }
134 
135  }
136  if(!DirectoryExists(TIMETABLE_DIR_NAME))
137  {
138  if(!CreateDir(TIMETABLE_DIR_NAME))
139  {
140  DirOpenError = true;
141  }
142  }
143  if(!DirectoryExists(PERFLOG_DIR_NAME))
144  {
145  if(!CreateDir(PERFLOG_DIR_NAME))
146  {
147  DirOpenError = true;
148  }
149  }
150  if(!DirectoryExists(SESSION_DIR_NAME))
151  {
152  if(!CreateDir(SESSION_DIR_NAME))
153  {
154  DirOpenError = true;
155  }
156  }
157  if(!DirectoryExists(IMAGE_DIR_NAME))
158  {
159  if(!CreateDir(IMAGE_DIR_NAME))
160  {
161  DirOpenError = true;
162  }
163  }
164  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
165  {
166  if(!CreateDir(FORMATTEDTT_DIR_NAME))
167  {
168  DirOpenError = true;
169  }
170  }
171  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
172  {
173  if(!CreateDir(USERGRAPHICS_DIR_NAME))
174  {
175  DirOpenError = true;
176  }
177  }
178  if(DirOpenError)
179  {
180  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
182  "program operation will be restricted");
183  }
184  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
185 
186  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
187  PopupMenu->AutoHotkeys = maManual; // as above
188 
189  Utilities = new TUtilities;
190  RailGraphics = new TRailGraphics();
191 
192  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
193  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
194  MainScreen->Width = DispW * 16;
195  MainScreen->Height = DispH * 16;
196 
199  Utilities->ScreenElementWidth = DispW;
201  HiddenScreen = new TImage(Interface);
202  HiddenScreen->Width = MainScreen->Width;
203  HiddenScreen->Height = MainScreen->Height;
207  Track = new TTrack;
208  AllRoutes = new TAllRoutes;
214  SelectBitmap = new Graphics::TBitmap;
215  SelectBitmap->PixelFormat = pf8bit;
216  SelectBitmap->Transparent = true;
221  LengthWarningSentFlag = false;
222  PasteWarningSentFlag = false; // added at v2.6.0
223  FillSelectionMessageSentFlag = false; // added at v2.6.0
224  LCManualLowerBarriersMessageSent = false; // added at v2.6.0
225  RecoverClipboardMessageSent = false; // added at v2.8.0
226  TooLongMessageSentFlag = false; //added at v2.9.1
227  TooShortMessageSentFlag = false; //added at v2.9.1
228 
229  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
230  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
231  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
232  ResetAll(0);
233 
234  TempTTFileName = "";
235 
240 
241  RouteFlashDuration = 0.0;
242  PointsFlashDuration = 0.0;
243 
244  FloatingLabel->Color = clB4G5R5;
245  TrackElementPanel->Color = clB5G5R4;
246  InfoPanel->Color = clB4G5R5;
247 
248  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME; // not changeable
249 
250  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
251  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
252  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
253  SigsOnLeftImage1->Transparent = true;
254  SigsOnLeftImage2->Transparent = true;
255  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
256  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
257  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
258  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
259  SigsOnRightImage1->Transparent = true;
260  SigsOnRightImage2->Transparent = true;
261  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
262  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
263 
264  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME; // default locations if not updated from Config.txt
265  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
266  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
267  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
268  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
269 
270  std::ifstream ConfigFile((CurDir + "\\Config.txt").c_str()); // added at v2.6.0 to set save & load directories for railways, timetables & session & to
271  if(ConfigFile.fail()) // no Config file //replace Signal.hnd, Background.col and GNU
272  {
273  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
274  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
275  SigsOnLeftImage1->Visible = true;
276  SigsOnLeftImage2->Visible = true;
277  SigsOnRightImage1->Visible = false;
278  SigsOnRightImage2->Visible = false;
279  ShowMessage(
280  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. " "It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; "
281  "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - " "you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>."
282  );
283  }
284  else
285  {
286  AnsiString ConfigStr = "";
287  do
288  {
289  Utilities->CheckAndReadFileString(ConfigFile, ConfigStr);
290  if(ConfigFile.eof())
291  {
292  break;
293  }
294  AnsiString ConfigValue = ConfigStr.SubString(9, ConfigStr.Length() - 8);
295  if(ConfigStr.SubString(1, 8) == "Signals=")
296  {
297  if(ConfigValue == "right")
298  {
299  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program, toggles Utilities->RHSignalFlag
300  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
302  {
304  }
305  else
306  {
308  }
309  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
310  SigsOnLeftImage1->Visible = false;
311  SigsOnLeftImage2->Visible = false;
312  SigsOnRightImage1->Visible = true;
313  SigsOnRightImage2->Visible = true;
314  }
315  else
316  {
317  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
318  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
319  SigsOnLeftImage1->Visible = true;
320  SigsOnLeftImage2->Visible = true;
321  SigsOnRightImage1->Visible = false;
322  SigsOnRightImage2->Visible = false;
323  }
324  }
325  if(ConfigStr.SubString(1, 8) == "BgndCol=")
326  {
327  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
328  Utilities->clTransparent = clB0G0R0; // default black background;
329  if(ConfigValue == "white")
330  {
331  Utilities->clTransparent = TColor(0xFFFFFF);
332  }
333  else if(ConfigValue == "blue")
334  {
335  Utilities->clTransparent = TColor(0x330000);
336  }
337  }
338  if(ConfigStr.SubString(1, 8) == "RLYLocn=")
339  {
340  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
341  {
342  SaveRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
343  LoadRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
344  }
345  }
346  else if(ConfigStr.SubString(1, 8) == "TTBLocn=")
347  {
348  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
349  {
350  TimetableDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
351  SaveTTDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
352  }
353  }
354  else if(ConfigStr.SubString(1, 8) == "SSNLocn=")
355  {
356  if(DirectoryExists(ConfigValue)) // e;se stays as original directory
357  {
358  LoadSessionDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
359  }
360  }
361  }
362  while(!ConfigFile.eof());
363  ConfigFile.close();
364  }
365  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
366  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
367  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
368  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
369  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
370  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
371  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
372  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
373  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
374  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
375  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
376  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
377  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
378  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
379  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
380  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
381  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
382  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
383  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
384  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
385  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
386  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
387  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
388  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
389  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
390  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
391  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
392  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
393  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
394  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
395  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
396  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
397  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
398  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
399  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
400  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
401  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
402  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
403  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
404  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
405  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
406  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
407  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
408  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
409  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
410  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
411  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
412  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
413  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
414  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
415  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
416  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
417  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
418  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
419  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
420  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
421  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
422  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
423  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
424  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
425  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
426  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
427  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
428  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
429  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
430  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
431  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
432  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
433  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
434  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
435  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
436  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
437  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
438  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
439  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
440  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
441  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
442  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
443  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
444  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
445  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
446  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
447  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
448  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
449  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
450  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
451  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
452  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
453  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
454  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
455  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
456  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
457  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
458  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
459  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
460  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
461  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
462  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
463  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
464  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
465  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
466  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
467  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
468  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
469  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
470  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
471  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
472  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
473  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
474  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
475  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
476  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
477  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
478  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
479  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
480  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
481  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
482  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
483  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
484  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
485  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
486  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
487  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
488  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
489  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
490  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
491  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
492  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
493  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
494  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
495  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
496  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
497  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
498  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
499  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
500  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
501  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
502  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
503  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
504  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
505  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
506  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
507  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
508  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
509  // below not in RailGraphics
510  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
511 
512  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
513  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
514  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
515  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
516  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
517  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
518  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
519  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
520  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
521  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
522  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
523  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
524  HomeButton->Glyph->LoadFromResourceName(0, "Home");
525  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
526  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
527  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
528  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
529  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
530  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
531  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
532  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
533  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
534  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
535  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
536  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
537  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
538  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
539  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
540  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
541  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
542  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
543  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
544  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
545  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
546  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
547  SigPrefConsecButton->Glyph->LoadFromResourceName(0, "PrefTop");
548  SigPrefNonConsecButton->Glyph->LoadFromResourceName(0, "PrefBottom");
549  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
550  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
551  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
552  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
553 
554  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
555  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
556  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
557  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
558  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
559  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
560  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
561  ManualLCDownImage->Picture->Bitmap->LoadFromResourceName(0, "ManualLCDownImage"); // new at v2.9.0
562 
563  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
564  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
565 
566  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
567  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
568  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
569  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
570  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
571  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
572 
573 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
574  RailwayIcon = new TPicture;
575  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
576  Icon = RailwayIcon->Icon;
577  Application->Icon = RailwayIcon->Icon;
578 */
579 
580  AnsiString NL = '\n';
581  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
582  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
583  "Start new shuttle service from a feeder";
584 
585  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
586 
587  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
588  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
589  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
590 
591  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
592  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " +
593  NL + "R";
594 
595  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
596 
597  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
598  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
599  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
600  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
601  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
602 
603  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
604  "Arrival time, departure time (with no events between) + location";
605 
606  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
607  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
608 
609  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
610  "and semicolons may only be used to" + NL + "separate service components.";
611 
612  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
613 
614  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
615 
616  TTLabel1->Caption = TTLabelStr1;
617  TTLabel2->Caption = TTLabelStr2;
618  TTLabel3->Caption = TTLabelStr3;
619  TTLabel4->Caption = TTLabelStr4;
620  TTLabel5->Caption = TTLabelStr5;
621  TTLabel6->Caption = TTLabelStr6;
622  TTLabel7->Caption = TTLabelStr7;
623  TTLabel9->Caption = TTLabelStr9;
624  TTLabel11->Caption = TTLabelStr11;
625  TTLabel12->Caption = TTLabelStr12;
626  TTLabel13->Caption = TTLabelStr13;
627  TTLabel15->Caption = TTLabelStr15;
628 
629  SelectBitmap->TransparentColor = Utilities->clTransparent;
630  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
632 
633  TextBox->Color = clB3G3R3;
634  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
635  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
636 
637  if((Screen->Width < 1024) || (Screen->Height < 768))
638  {
639  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
640  }
641  SkipFormResizeEvent = true; // added at v2.1.0
642  MasterClock->Enabled = true;
643  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
644  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
645  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
646  // has to come after Visible = true or doesn't show
647  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
648  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
649  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
650  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
651  AllSetUpFlag = true;
652  MissedTicks = 0;
653  TotalTicks = 0;
655  SetLevel1Mode(131); // to reset background colour mode menu choices
656  Screen->Cursor = TCursor(-2); // Arrow
657  SkipFormResizeEvent = false; // added at v2.1.0
658  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
659 
660  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
661  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
662  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
663  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
664  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
665  HighlightPanel->Color = TColor(0x33CCFF);
667  MTBFEditBox->Visible = false; // new at v2.4.0
668  MTBFLabel->Visible = false;
672  CancelSelectionFlag = false;
673  TTStartTimePtr = 0;
674  TTFirstServicePtr = 0;
675  TTLastServicePtr = 0;
676  Track->OverrideAndHideSignalBridgeMessage = false; // added at v2.5.1 to allow facing signals before bridges - with a warning
677  ConflictPanel->Visible = false;
678  TTClockAdjustWarningPanel->Visible = false;
679  TTClockAdjustWarningHide = false;
680  TwoLocationNamePanel->Visible = false;
681  TwoLocationNamePanelHide = false;
682  LastNonCtrlOrShiftKeyDown = -1; // set to no key
683  ClipboardChecked = false;
684  MMoveTrackSelFlag = false;
685  MMovePrefDirSelFlag = false;
689 
690  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
691 
692  // below added at v2.4.0 so able to load session files with the correct decimal point
693  Utilities->DecimalPoint = '.'; // default case is full stop
694  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
696  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
697  {
698  Utilities->SetLocaleResultOK = false;
699  }
700  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
701  struct lconv *conv = &Locale;
702  // read the locality conversion structure
703  conv = localeconv(); // this is what updates the structure
704  Utilities->DecimalPoint = conv->decimal_point[0];
705  }
706 
707  catch(const EFOpenError &e)
708  {
709  TMsgDlgButtons But;
710  But << mbOK;
711  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
712  Application->Terminate();
713  }
714 
715  catch(const Exception &e)
716  {
717  TMsgDlgButtons But;
718  But << mbOK;
719  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
720  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
721  ErrorLog(115, e.Message);
722  Application->Terminate();
723  }
724 }
725 
726 // ---------------------------------------------------------------------------
727 
729 {
730  // destructor
731  try
732  {
733  // rewrite ConfigFile with signal handedness, background colour & InitialDir values (may be same but no matter)
734  AnsiString ColourStr = "", SignalStr = "";
735  remove((CurDir + "\\Config.txt").c_str());
736  std::ofstream ConfigFile((CurDir + "\\Config.txt").c_str());
737  ColourStr = "black";
738  SignalStr = "left";
739  if(Utilities->clTransparent == TColor(0xFFFFFF))
740  {
741  ColourStr = "white";
742  }
743  else if(Utilities->clTransparent == TColor(0x330000))
744  {
745  ColourStr = "blue";
746  }
748  {
749  SignalStr = "right";
750  }
751  ConfigFile << AnsiString("Signals=") << SignalStr << '\n';
752  ConfigFile << AnsiString("BgndCol=") << ColourStr << '\n';
753  ConfigFile << AnsiString("RLYLocn=") << AnsiString(LoadRailwayDialog->InitialDir) << '\n';
754  ConfigFile << AnsiString("TTBLocn=") << AnsiString(TimetableDialog->InitialDir) << '\n';
755  ConfigFile << AnsiString("SSNLocn=") << AnsiString(LoadSessionDialog->InitialDir) << '\n';
756  ConfigFile.close();
757 
758  SkipFormResizeEvent = true; // added at v2.1.0
759  delete NonSigRouteStartMarker;
760  delete SigRouteStartMarker;
761  delete AutoRouteStartMarker;
762  delete PointFlash;
763  delete SelectBitmap;
764  delete TrainController;
765  delete EveryPrefDir;
766  delete SelectPrefDir;
767  delete ConstructRoute;
768  delete ConstructPrefDir;
769  delete AllRoutes;
770  delete Track;
771  delete TextHandler;
772  delete HiddenDisplay;
773  delete HiddenScreen;
774  delete Display;
775  delete RailGraphics;
776  delete Utilities;
777  DeleteFile(TempTTFileName); // added at v2.5.0 to prevent temporary files building up
778  }
779  catch(const Exception &e)
780  {
781  ErrorLog(116, e.Message);
782  }
783 }
785 
786 // ---------------------------------------------------------------------------
787 
788 void __fastcall TInterface::FormCreate(TObject *Sender)
789 {
790  // these functions have to be defined here to take effect when application activated & deactivated
791  try
792  {
793  Application->OnDeactivate = AppDeactivate;
794  Application->OnActivate = AppActivate;
795  }
796  catch(const Exception &e)
797  {
798  ErrorLog(117, e.Message);
799  }
800 }
801 
802 // ---------------------------------------------------------------------------
803 
804 void __fastcall TInterface::AppDeactivate(TObject *Sender)
805 {
806  // pause operation if operating & stop the master clock
807  try
808  {
810  {
811  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
812  {
813  // by Matt Blades 30/06/11
817  Screen->Cursor = TCursor(-2); // Arrow
818  Track->RouteFlashFlag = false;
819  ClearandRebuildRailway(48); // to get rid of displayed route
820  }
821  if(Track->PointFlashFlag)
822  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
823  {
825  Track->PointFlashFlag = false;
827  Screen->Cursor = TCursor(-2); // Arrow
828  }
831  }
832  MasterClock->Enabled = false;
833  ClipboardChecked = false; // added at v2.8.0 to force a check of the clipboard (via ClockTimer2 & SetTrackModeMenu)
834  }
835  catch(const Exception &e)
836  {
837  ErrorLog(118, e.Message);
838  }
839 }
840 
841 // ---------------------------------------------------------------------------
842 
843 void __fastcall TInterface::AppActivate(TObject *Sender)
844 {
845  // restart the master clock providing Interface constructor has run
846  try
847  {
848  if(AllSetUpFlag)
849  {
850  MasterClock->Enabled = true;
851  ClipboardChecked = false; // at v2.9.0 added here too as for some unknown reason it doesn't always work when just in deactivate
852  }
853  }
854  catch(const Exception &e)
855  {
856  ErrorLog(119, e.Message);
857  }
858 }
859 
860 // ---------------------------------------------------------------------------
861 
862 UnicodeString TInterface::GetVersion()
863 {
864  DWORD VersionHandle;
865  DWORD VersionSize;
866  LPBYTE pBuffer;
867  UnicodeString strVersion = L"N/A";
868 
869  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
870  if(VersionSize)
871  {
872  pBuffer = new BYTE[VersionSize];
873 
874  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
875  {
876  VS_FIXEDFILEINFO *fi;
877  UINT buflen;
878 
879  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
880  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
881  {
882  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
883  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS));
884  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
885  }
886  }
887  delete[]pBuffer;
888  }
889  return(L" v" + strVersion);
890 }
891 
892 // ---------------------------------------------------------------------------
893 // Track Build Interface
894 // ---------------------------------------------------------------------------
895 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
896 {
897  try
898  {
899  TrainController->LogEvent("BuildTrackMenuItemClick");
900  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
902  SetLevel1Mode(0);
903  Utilities->CallLogPop(1159);
904  }
905  catch(const Exception &e)
906  {
907  ErrorLog(120, e.Message);
908  }
909 }
910 // ---------------------------------------------------------------------------
911 
912 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
913 {
914  try
915  {
916  TrainController->LogEvent("AddTrackButtonClick");
917  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
919  SetLevel1Mode(38);
922  Utilities->CallLogPop(1162);
923  }
924  catch(const Exception &e)
925  {
926  ErrorLog(121, e.Message);
927  }
928 }
929 
930 // ---------------------------------------------------------------------------
931 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
932 {
933  try
934  {
935  TrainController->LogEvent("SpeedButtonClick");
936  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
937  ReselectMenuItem->Enabled = false;
938  if(((TSpeedButton*)Sender)->Down)
939  {
940  CurrentSpeedButton = (TSpeedButton*)Sender;
941 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
942  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
943  if((Level2TrackMode == TrackSelecting) && (CurrentSpeedButton->Tag != 144))
944  // new addition at v2.6.0 to fill selected area with the element corresponding to CurrentSpeedButton
945  {
946  // 144 = level crossing & these not permitted
947  if((SelectRect.left != SelectRect.right) && (SelectRect.top != SelectRect.bottom) && SelectionValid)
948  {
949  Screen->Cursor = TCursor(-11); // Hourglass;
950  InfoPanel->Caption = "SELECTING: Filling area with chosen element";
951  bool FillSelectionFlag = false;
953  {
954  UnicodeString MessageStr =
955  "Click 'Yes' to fill the area with the chosen element or 'No' to abort.\n" "Existing elements won't be overwritten although track can\n"
956  "have platforms and non-station named location elements added.\n\nThis message will not be shown again.";
957  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
958  if(button == IDYES)
959  {
960  FillSelectionFlag = true;
961  }
962  }
963  if(FillSelectionFlag || FillSelectionMessageSentFlag)
964  {
965  bool TrackLinkingRequiredFlag = true;
966  for(int HLoc = SelectRect.left; HLoc < SelectRect.right; HLoc++)
967  {
968  for(int VLoc = SelectRect.top; VLoc < SelectRect.bottom; VLoc++)
969  {
970  if((HLoc != SelectRect.right) || (VLoc != SelectRect.bottom))
971  {
972  Track->PlotAndAddTrackElement(3, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, false);
973 // false for internal checks
974  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
975  }
976  else
977  {
978  Track->PlotAndAddTrackElement(4, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, true);
979 // internal checks true for last plot
980  }
981  }
982  }
983  }
984  Track->SetTrackFinished(false);
985  ClearandRebuildRailway(80); // to remove selection outline
986  SelectionValid = false;
987  Track->CopyFlag = false;
989  ResetSelectRect();
990  SetLevel1Mode(139);
992  SetLevel2TrackMode(66);
994  Screen->Cursor = TCursor(-2); // Arrow
995  ReselectMenuItem->Enabled = true; // allow when filling areas
996  }
997  }
998  }
999  else
1000  {
1001  CurrentSpeedButton = 0;
1002  }
1003  Utilities->CallLogPop(1163);
1004  }
1005  catch(const Exception &e)
1006  {
1007  ErrorLog(122, e.Message);
1008  }
1009 }
1010 
1011 // ---------------------------------------------------------------------------
1012 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
1013 {
1014  try
1015  {
1016  TrainController->LogEvent("TrackOKButtonClick");
1017  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
1018  SelectionValid = false;
1020  bool LocError;
1021  int HLoc, VLoc;
1022  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
1023 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
1024  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
1025  // if successful repositions TrackVector & builds TrackMap
1026  {
1027  if(LocError) // links not complete or other error - show offending element
1028  {
1029  while((Display->DisplayOffsetH - HLoc) > 0)
1030  {
1031  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
1032  }
1033  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
1034  {
1036  }
1037  while((Display->DisplayOffsetV - VLoc) > 0)
1038  {
1039  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
1040  }
1041  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
1042  {
1044  }
1046  Display->InvertElement(0, HLoc * 16, VLoc * 16);
1047  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
1048  ClearandRebuildRailway(1); // to clear inversion
1050  SetLevel1Mode(39);
1051  Level2TrackMode = AddTrack; // go to add track regardless of where started from
1052  SetLevel2TrackMode(3);
1053  Utilities->CallLogPop(0);
1054  return;
1055  }
1056  else
1057  {
1058  // reach here if there are no track elements
1059  ShowMessage("Unable to set any track links");
1061  SetLevel1Mode(40);
1063  SetLevel2TrackMode(4); // go to add track regardless of where started from
1064  Utilities->CallLogPop(1);
1065  return;
1066  }
1067  }
1068  else
1069  {
1070  // success so far as track is concerned ('TrackFinished' set in TryToConnectTrack)
1071  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
1072  }
1073 // success if reach here ('TrackFinished' set in TryToConnectTrack)
1074  if(Level2TrackMode == AddTrack)
1075  {
1078  SetLevel1Mode(41);
1079  SetLevel2TrackMode(5);
1080  }
1081  else
1082  {
1084  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
1085  }
1086  ShowMessage("Successful Completion");
1087  Utilities->CallLogPop(2);
1088  }
1089  catch(const Exception &e)
1090  {
1091  ErrorLog(3, e.Message);
1092  }
1093 }
1094 
1095 // ---------------------------------------------------------------------------
1096 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
1097 {
1098  try
1099  {
1100  TrainController->LogEvent("SetGapsButtonClick");
1101  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
1102  SelectionValid = false;
1103  ReselectMenuItem->Enabled = false;
1105  SetLevel1Mode(42);
1107  SetLevel2TrackMode(6);
1108  Utilities->CallLogPop(1164);
1109  }
1110  catch(const Exception &e)
1111  {
1112  ErrorLog(123, e.Message);
1113  }
1114 }
1115 
1116 // ---------------------------------------------------------------------------
1117 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
1118 {
1119  try
1120  {
1121  TrainController->LogEvent("AddTextButtonClick");
1122  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
1124  SetLevel1Mode(43);
1126  SetLevel2TrackMode(7);
1127  Utilities->CallLogPop(1165);
1128  }
1129  catch(const Exception &e)
1130  {
1131  ErrorLog(124, e.Message);
1132  }
1133 }
1134 
1135 // ---------------------------------------------------------------------------
1136 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
1137 {
1138  try
1139  {
1140  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1141  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1143  SetLevel1Mode(44);
1145  SetLevel2TrackMode(8);
1146  Utilities->CallLogPop(1166);
1147  }
1148  catch(const Exception &e)
1149  {
1150  ErrorLog(125, e.Message);
1151  }
1152 }
1153 
1154 // ---------------------------------------------------------------------------
1155 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1156 {
1157  try
1158  {
1159  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1160  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1161  if(Key == '\x0D') // CR
1162  {
1163  if(TextBox->Text != "") // if blank then don't save
1164  {
1165  if(Display->GetFont()->Color == clB5G5R5) // white
1166  {
1167  TFont *TempFont = new TFont;
1168  TempFont->Assign(Display->GetFont());
1169  TempFont->Color = clB0G0R0; // change to black for vector & saving
1170  Display->SetFont(TempFont);
1171  delete TempFont;
1172  }
1173  TFont *DisplayFont = Display->GetFont();
1174  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1175  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1177  ResetChangedFileDataAndCaption(12, true); // moved here from MainScreenMouseDown2 after 2.7.0 in case nothing changed
1178  }
1179  EditMenu->Enabled = true;
1180  TextBox->Visible = false;
1181  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1182  }
1183  else if(Key == '\x1B') // escape
1184  {
1185  if(TextBox->Text != "")
1186  {
1187  ResetChangedFileDataAndCaption(28, true); // added here after 2.7.0 in case replaced existing text (which is selected) with blank
1188  }
1189  TextBox->Visible = false;
1190  }
1191  Utilities->CallLogPop(3);
1192  }
1193  catch(const Exception &e)
1194  {
1195  ErrorLog(4, e.Message);
1196  }
1197 }
1198 
1199 // ---------------------------------------------------------------------------
1200 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1201 {
1202  try
1203  {
1204  TrainController->LogEvent("LocationNameButtonClick");
1205  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1207  SetLevel1Mode(45);
1209  SetLevel2TrackMode(9);
1210  Utilities->CallLogPop(1167);
1211  }
1212  catch(const Exception &e)
1213  {
1214  ErrorLog(126, e.Message);
1215  }
1216 }
1217 
1218 // ---------------------------------------------------------------------------
1219 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1220 {
1221  try
1222  {
1223  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1224  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1225  if(Track->LNPendingList.empty())
1226  {
1227  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1229  SetLevel1Mode(46);
1231  SetLevel2TrackMode(10);
1232  Utilities->CallLogPop(4);
1233  return;
1234  }
1235  if(Key == '\x1B') // escape
1236  {
1237  Track->LNPendingList.clear(); // get rid of existing entry
1239  SetLevel1Mode(47);
1241  SetLevel2TrackMode(11);
1242  Utilities->CallLogPop(5);
1243  return;
1244  }
1245  if(Key == '\x0D')
1246  {
1247  Screen->Cursor = TCursor(-11); // Hourglass;
1249  ResetChangedFileDataAndCaption(8, true); // moved here after 2.7.0 from mainScreenMouseDown2 in case nothing changed
1250  AnsiString ExistingName;
1251  LocationNameTextBox->Text = LocationNameTextBox->Text.Trim();
1252 // added at v2.6.1 to prevent added spaces because they skip the different location same name chack
1253  if(Track->LNPendingList.front() > -1)
1254  {
1255  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1256  }
1257  else
1258  {
1259  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1260  }
1261  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1262  {
1263  // name allocated to a different location
1264  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1265  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1266  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1267  if(button == IDNO)
1268  {
1269  Track->LNPendingList.clear(); // get rid of existing entry
1270  Screen->Cursor = TCursor(-2); // Arrow
1272  SetLevel1Mode(48);
1274  SetLevel2TrackMode(12);
1275  Utilities->CallLogPop(6);
1276  return;
1277  }
1279  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1280  int HPos, VPos;
1281  bool UseExistingPosition = false;
1282  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1283  {
1284  ;
1285  } // condition not used
1286 
1287  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1288  // but, the location to be named may also have an existing name, in which case that needs to be erased
1289  // and the position re-used
1290  if(ExistingName != "")
1291  {
1292  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1293  {
1294  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1295  }
1296  }
1297  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1298  Screen->Cursor = TCursor(-2); // Arrow
1300  SetLevel1Mode(49);
1302  SetLevel2TrackMode(13);
1303  Utilities->CallLogPop(7);
1304  return;
1305  }
1306  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1307  {
1308  // same name being entered again
1309  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1310  // but in case the name is not already in text vector erase it and re-add it
1311  // if it wasn't in the vector erasing it has no effect
1312  int HPos, VPos;
1313  bool UseExistingPosition = false;
1314  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1315  {
1316  UseExistingPosition = true;
1317  }
1318  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1319  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1320  Screen->Cursor = TCursor(-2); // Arrow
1322  SetLevel1Mode(50);
1324  SetLevel2TrackMode(14);
1325  Utilities->CallLogPop(8);
1326  return;
1327  }
1328  else
1329  {
1330  // either a new name for an unnamed location, or a different name for a named location
1331  // check validity of entry
1332  AnsiString LocStr = LocationNameTextBox->Text;
1333  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1334  LocationNameTextBox->Text = LocStr; // reset this as used below
1335 /* drop this, now covered by ...Trim() above
1336  //strip leading spaces
1337  while((LocStr != "") && (LocStr[1] == ' '))
1338  {
1339  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1340  }
1341 */
1342  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1343  {
1344  Screen->Cursor = TCursor(-2); // Arrow
1345  ShowMessage("Location name can't begin with a number");
1347  SetLevel1Mode(51);
1349  SetLevel2TrackMode(15);
1350  Utilities->CallLogPop(776);
1351  return;
1352  }
1353  if(LocStr.Length() > 50)
1354  {
1355  Screen->Cursor = TCursor(-2); // Arrow
1356  ShowMessage("Location name too long, 50 characters maximum");
1358  SetLevel1Mode(122);
1360  SetLevel2TrackMode(55);
1361  Utilities->CallLogPop(1735);
1362  return;
1363  }
1364  for(int x = 1; x <= LocStr.Length(); x++)
1365  {
1366  char Ch = LocStr[x];
1367  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1368  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1369  {
1370  Screen->Cursor = TCursor(-2); // Arrow
1371  ShowMessage(
1372  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1374  SetLevel1Mode(52);
1376  SetLevel2TrackMode(16);
1377  Utilities->CallLogPop(777);
1378  return;
1379  }
1380  }
1381  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1382  {
1383  Screen->Cursor = TCursor(-2); // Arrow
1384  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1386  SetLevel1Mode(53);
1388  SetLevel2TrackMode(17);
1389  Utilities->CallLogPop(778);
1390  return;
1391  }
1392  Track->EnterLocationName(2, LocStr, false);
1393  // need to check if the location already has a name, and if so erase it from the textvector
1394  int HPos, VPos;
1395  bool UseExistingPosition = false;
1396  if(ExistingName != "")
1397  {
1398  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1399  {
1400  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1401  }
1402  }
1403  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1404  Screen->Cursor = TCursor(-2); // Arrow
1406  SetLevel1Mode(54);
1408  SetLevel2TrackMode(18);
1409  Utilities->CallLogPop(9);
1410  return;
1411  }
1412  }
1413  Screen->Cursor = TCursor(-2); // Arrow
1414  Utilities->CallLogPop(10);
1415  }
1416  catch(const Exception &e)
1417  {
1418  ErrorLog(5, e.Message);
1419  }
1420 }
1421 
1422 // ---------------------------------------------------------------------------
1423 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1424 {
1425  try
1426  {
1427  TrainController->LogEvent("SetLengthsButtonClick");
1428  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1429  SelectLengthsFlag = false;
1430  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1432  SetLevel1Mode(55);
1434  SetLevel2TrackMode(19);
1435  Utilities->CallLogPop(1168);
1436  }
1437  catch(const Exception &e)
1438  {
1439  ErrorLog(127, e.Message);
1440  }
1441 }
1442 
1443 // ---------------------------------------------------------------------------
1444 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1445 {
1446  try
1447  {
1448  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1449  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1450  ResetChangedFileDataAndCaption(4, true); // moved here after 2.7.0 so only need to save if something changed
1451  int Dist = 0, SpeedLimit = 0;
1452  AnsiString DistanceStr = DistanceBox->Text;
1453  if(SelectLengthsFlag && (DistanceStr == ""))
1454  {
1455  DistanceStr = "No change";
1456  }
1457  AnsiString SpeedStr = SpeedLimitBox->Text;
1458  if(SelectLengthsFlag && (SpeedStr == ""))
1459  {
1460  SpeedStr = "No change";
1461  }
1462  if(SelectLengthsFlag)
1463  {
1464  if(DistanceStr == "No change")
1465  {
1466  Dist = -1; // i.e.don't change
1467  }
1468  if(SpeedStr == "No change")
1469  {
1470  SpeedLimit = -1; // i.e.don't change
1471  }
1472  }
1473  else
1474  {
1475  if(DistanceStr == AnsiString(OverallDistance))
1476  {
1477  Dist = -1; // i.e.don't change
1478  }
1479  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1480  {
1481  SpeedLimit = -1; // i.e.don't change
1482  }
1483  }
1484  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1485  {
1486  ShowMessage("One or more entries too long");
1487  Utilities->CallLogPop(11);
1488  return;
1489  }
1490  if((DistanceStr == "") || (SpeedStr == ""))
1491  {
1492  ShowMessage("One or more entries blank");
1493  Utilities->CallLogPop(12);
1494  return;
1495  }
1496  if(SelectLengthsFlag && (Dist != -1))
1497  {
1498  for(int x = 1; x <= DistanceStr.Length(); x++)
1499  {
1500  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1501  {
1502  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1503  Utilities->CallLogPop(1415);
1504  return;
1505  }
1506  }
1507  }
1508  if(!SelectLengthsFlag)
1509  {
1510  for(int x = 1; x <= DistanceStr.Length(); x++)
1511  {
1512  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1513  {
1514  ShowMessage("Distance must be a positive whole number");
1515  Utilities->CallLogPop(13);
1516  return;
1517  }
1518  }
1519  }
1520  if(SelectLengthsFlag && (SpeedLimit != -1))
1521  {
1522  for(int x = 1; x <= SpeedStr.Length(); x++)
1523  {
1524  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1525  {
1526  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1527  Utilities->CallLogPop(1416);
1528  return;
1529  }
1530  }
1531  }
1532  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1533  {
1534  for(int x = 1; x <= SpeedStr.Length(); x++)
1535  {
1536  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1537  {
1538  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1539  Utilities->CallLogPop(14);
1540  return;
1541  }
1542  }
1543  }
1544  if(Dist != -1)
1545  {
1546  Dist = DistanceStr.ToInt();
1547  }
1548  if(SpeedLimit != -1)
1549  {
1550  SpeedLimit = SpeedStr.ToInt();
1551  }
1552 /* don't need this with new condition below
1553  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1554  {
1555  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1556  Dist = 20;
1557  }
1558 */
1559  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1560  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1561  {
1562  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1563  Utilities->CallLogPop(15);
1564  return;
1565  }
1566  DistanceBox->Text = "";
1567  SpeedLimitBox->Text = "";
1568  if(SelectLengthsFlag)
1569  {
1570  int LowSelectHLoc = SelectBitmapHLoc;
1571  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1572  int LowSelectVLoc = SelectBitmapVLoc;
1573  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1574  bool FoundFlag;
1575  bool NamedLocPresent = false;
1576  if((Dist != -1) && (Dist != DefaultTrackLength))
1577  {
1578  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1579  {
1580  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1581  {
1583  {
1584  NamedLocPresent = true;
1585  }
1586  }
1587  }
1588  }
1589  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1590  {
1591  if(!TooShortMessageSentFlag) //added at v2.9.1
1592  {
1593  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might be too unrealistic.\n\nThis message will not be shown again.");
1594  TooShortMessageSentFlag = true; //added at v2.9.1
1595  }
1596  }
1597  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1598  {
1599  if(!TooLongMessageSentFlag) //added at v2.9.1
1600  {
1601  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might be too unrealistic.\n\nThis message will not be shown again.");
1602  TooLongMessageSentFlag = true; //added at v2.9.1
1603  }
1604  }
1605  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1606  {
1607  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1608  {
1609  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1610  if(FoundFlag)
1611  {
1612  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1613  {
1614  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1615  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1616  {
1617  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1618  }
1619  }
1620  if(SpeedLimit > -1)
1621  {
1622  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1623  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1624  {
1625  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1626  }
1627  }
1628  }
1629  }
1630  }
1631  TrackLengthPanel->Visible = false;
1632  SelectLengthsFlag = false; // go back to normal distance setting mode
1633  }
1634  else
1635  {
1636  SetTrackLengths(1, Dist, SpeedLimit);
1637  }
1639  SetLevel1Mode(57);
1641  SetLevel2TrackMode(21);
1642  Utilities->CallLogPop(16);
1643  }
1644  catch(const Exception &e)
1645  {
1646  ErrorLog(6, e.Message);
1647  }
1648 }
1649 
1650 // ---------------------------------------------------------------------------
1651 void __fastcall TInterface::LengthCancelButtonClick(TObject * Sender)
1652 {
1653  try
1654  {
1655  TrainController->LogEvent("LengthCancelButtonClick");
1656  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1657  DistanceBox->Text = "";
1658  SpeedLimitBox->Text = "";
1659  TrackLengthPanel->Visible = false;
1660  SelectLengthsFlag = false; // go back to normal distance setting mode
1662  SetLevel1Mode(59);
1664  SetLevel2TrackMode(23);
1665  Utilities->CallLogPop(1169);
1666  }
1667  catch(const Exception &e)
1668  {
1669  ErrorLog(128, e.Message);
1670  }
1671 }
1672 
1673 // ---------------------------------------------------------------------------
1674 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1675 {
1676  try
1677  {
1678  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1679  TMsgDlgButtons Buttons;
1680  Buttons << mbYes << mbNo;
1681  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1682  {
1683  // leave all as was before
1684  Utilities->CallLogPop(17);
1685  return;
1686  }
1687  else
1688  {
1689  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1690  ResetChangedFileDataAndCaption(25, true); // added after 2.7.0 so only need to save if something changed
1691  DistanceBox->Text = "";
1692  SpeedLimitBox->Text = "";
1693  if(SelectLengthsFlag)
1694  {
1695  int LowSelectHLoc = SelectBitmapHLoc;
1696  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1697  int LowSelectVLoc = SelectBitmapVLoc;
1698  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1699  bool FoundFlag;
1700  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1701  {
1702  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1703  {
1704  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1705  if(FoundFlag)
1706  {
1708  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1709  {
1711  }
1713  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1714  {
1716  }
1717  }
1718  }
1719  }
1720  TrackLengthPanel->Visible = false;
1721 // ClearandRebuildRailway(47); don't need this
1722  SelectLengthsFlag = false; // go back to normal distance setting mode
1723  }
1724  else
1725  {
1726  TrackLengthPanel->Visible = false;
1727  bool FoundFlag;
1728  if(ConstructPrefDir->PrefDirSize() == 0)
1729  {
1730  Utilities->CallLogPop(1120);
1731  return;
1732  }
1733  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1734  {
1735  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1736  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1737  FoundFlag));
1738  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1739  // only set the relevant track to default length & speed limit
1740  {
1741  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1742  {
1743  TrackElement.Length01 = DefaultTrackLength;
1744  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1745  }
1746  else
1747  {
1748  TrackElement.Length23 = DefaultTrackLength;
1749  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1750  }
1751  }
1752  else // any other 1 track element, including platforms being present
1753  {
1754  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1755  {
1756  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1757  AnsiString(TrackElement.VLoc));
1758  }
1759  TrackElement.Length01 = DefaultTrackLength;
1760  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1761  TrackElement.Length23 = -1;
1762  TrackElement.SpeedLimit23 = -1;
1763  }
1764  }
1765  }
1767  SetLevel1Mode(61);
1769  SetLevel2TrackMode(25);
1770  }
1771  Utilities->CallLogPop(18);
1772  }
1773  catch(const Exception &e)
1774  {
1775  ErrorLog(7, e.Message);
1776  }
1777 }
1778 
1779 // ---------------------------------------------------------------------------
1780 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1781 {
1782  try
1783  {
1784  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1785  TMsgDlgButtons Buttons;
1786  Buttons << mbYes << mbNo;
1787  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1788  {
1789  // leave all as was before
1790  Utilities->CallLogPop(19);
1791  return;
1792  }
1793  else
1794  {
1796  }
1797  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1798  ResetChangedFileDataAndCaption(26, true); // added after 2.7.0 so only need to save if something changed
1799  DistanceBox->Text = "";
1800  SpeedLimitBox->Text = "";
1801  TrackLengthPanel->Visible = false;
1802  SelectLengthsFlag = false; // go back to normal distance setting mode
1804  SetLevel1Mode(63);
1806  SetLevel2TrackMode(27);
1807  Utilities->CallLogPop(20);
1808  }
1809  catch(const Exception &e)
1810  {
1811  ErrorLog(8, e.Message);
1812  }
1813 }
1814 
1815 // ---------------------------------------------------------------------------
1816 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1817 {
1818  try
1819  {
1820  TrainController->LogEvent("ExitTrackButtonClick");
1821  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1822  if(Level2TrackMode == CutMoving)
1823  {
1824  Level2TrackMode = Pasting; // to paste the selection
1825  SetLevel2TrackMode(53);
1826  }
1827  DevelopmentPanel->Visible = false; // development use only
1828  ScreenGridFlag = false;
1829  SelectionValid = false;
1830  Track->SelectGraphicVector.clear();
1831  // delete all unwanted TPictures in UserGraphicMap
1832  if(!Track->UserGraphicMap.empty()) // if empty skip it
1833  {
1834  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1835  do
1836  {
1837  bool GraphicFoundInVector = false;
1838  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1839  {
1840  if(UGMIt->first == UGVIt->FileName)
1841  {
1842  GraphicFoundInVector = true;
1843  break;
1844  }
1845  }
1846  if(!GraphicFoundInVector)
1847  {
1848  delete UGMIt->second;
1849  Track->UserGraphicMap.erase(UGMIt);
1850  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1851  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1852  }
1853  else
1854  {
1855  UGMIt++;
1856  }
1857  }
1858  while(UGMIt != Track->UserGraphicMap.end());
1859  }
1860  Level1Mode = BaseMode;
1861  SetLevel1Mode(2);
1862  Utilities->CallLogPop(1170);
1863  }
1864  catch(const Exception &e)
1865  {
1866  ErrorLog(129, e.Message);
1867  }
1868 }
1869 
1870 // ---------------------------------------------------------------------------
1871 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1872 {
1873  try
1874  {
1875  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1876  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1877  if(TextOrUserGraphicGridVal == 1)
1878  {
1880  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1881  }
1882  else if(TextOrUserGraphicGridVal == 2)
1883  {
1885  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1886  }
1887  else if(TextOrUserGraphicGridVal == 4)
1888  {
1890  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1891  }
1892  else if(TextOrUserGraphicGridVal == 8)
1893  {
1895  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1896  }
1897  else
1898  {
1900  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1901  }
1902  Utilities->CallLogPop(1171);
1903  }
1904  catch(const Exception &e)
1905  {
1906  ErrorLog(130, e.Message);
1907  }
1908 }
1909 
1910 // ---------------------------------------------------------------------------
1911 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1912 {
1913  try
1914  {
1915  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1916  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1918  {
1920  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1921  }
1923  {
1925  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1926  }
1928  {
1930  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1931 // set all signal glyphs to ground signals
1933  }
1934  else
1935  {
1937  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1938 // set all signal glyphs to normal signals
1940  }
1941  Utilities->CallLogPop(1869);
1942  }
1943  catch(const Exception &e)
1944  {
1945  ErrorLog(180, e.Message);
1946  }
1947 }
1948 
1949 // ---------------------------------------------------------------------------
1950 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1951 {
1952  try
1953  {
1954  TrainController->LogEvent("FontButtonClick");
1955  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1956  FontDialog->Font = Display->GetFont(); // sets the dialog box font to the currently used font
1957  FontDialog->Execute(); // this displays the dialog box
1958  if(FontDialog->Font->Color == clB5G5R5) // white
1959  {
1960  FontDialog->Font->Color = clB0G0R0; // black - don't store white in font, will display black as white on dark backgrounds
1961  }
1962  Display->SetFont(FontDialog->Font); // sets the displayed font to the output from the dialog box
1963  if(TextBox->Visible)
1964  {
1965  TextBox->SetFocus();
1966  }
1967  else if(LocationNameTextBox->Visible)
1968  {
1969  LocationNameTextBox->SetFocus();
1970  }
1971  Utilities->CallLogPop(1172);
1972  }
1973  catch(const Exception &e)
1974  {
1975  ErrorLog(131, e.Message);
1976  }
1977 }
1978 
1979 // ---------------------------------------------------------------------------
1980 
1981 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1982 {
1983  try
1984  {
1985  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1986  if(ScreenGridFlag)
1987  {
1988  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1989  ScreenGridFlag = false;
1990  }
1991  else
1992  {
1993  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1994  ScreenGridFlag = true;
1995  }
1997  Utilities->CallLogPop(89);
1998  }
1999  catch(const Exception &e)
2000  {
2001  ErrorLog(33, e.Message);
2002  }
2003 }
2004 
2005 // ---------------------------------------------------------------------------
2006 // PrefDir Interface
2007 // ---------------------------------------------------------------------------
2008 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
2009 {
2010  try
2011  {
2012  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
2013  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
2015  SetLevel1Mode(3);
2016  Utilities->CallLogPop(1173);
2017  }
2018  catch(const Exception &e)
2019  {
2020  ErrorLog(132, e.Message);
2021  }
2022 }
2023 
2024 // ---------------------------------------------------------------------------
2025 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
2026 {
2027  try
2028  {
2029  TrainController->LogEvent("AddPrefDirButtonClick");
2030  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
2031  if(ConstructPrefDir->PrefDirSize() == 0)
2032  {
2033  ShowMessage("No preferred direction selection");
2034  Utilities->CallLogPop(22);
2035  return;
2036  }
2037  Screen->Cursor = TCursor(-11); // Hourglass;
2039  {
2041  }
2043  SetLevel1Mode(4);
2044  Screen->Cursor = TCursor(-2); // Arrow
2045  Utilities->CallLogPop(23);
2046  }
2047  catch(const Exception &e)
2048  {
2049  ErrorLog(10, e.Message);
2050  }
2051 }
2052 
2053 // ---------------------------------------------------------------------------
2054 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
2055 {
2056  try
2057  {
2058  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
2059  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
2060  TMsgDlgButtons Buttons;
2061  Buttons << mbYes << mbNo;
2062  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
2063  {
2064  Utilities->CallLogPop(24);
2065  return;
2066  }
2067  // leave all as was before pressed DeleteAllPrefDirButton
2068  else
2069  {
2074  SetLevel1Mode(5);
2075  }
2076  Utilities->CallLogPop(25);
2077  }
2078  catch(const Exception &e)
2079  {
2080  ErrorLog(11, e.Message);
2081  }
2082 }
2083 // ---------------------------------------------------------------------------
2084 
2085 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
2086 {
2087  try
2088  {
2089  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
2090  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
2091  ResetChangedFileDataAndCaption(18, false);
2092 // RlyFile = false; - don't alter this just for PrefDir changes
2093  Screen->Cursor = TCursor(-11); // Hourglass;
2094  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
2095  {
2098  }
2101  SetLevel1Mode(81); // all PrefDir truncated
2102  Screen->Cursor = TCursor(-2); // Arrow
2103  Utilities->CallLogPop(1591);
2104  }
2105  catch(const Exception &e)
2106  {
2107  ErrorLog(46, e.Message);
2108  }
2109 }
2110 
2111 // ---------------------------------------------------------------------------
2112 
2113 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
2114 {
2115  try
2116  {
2117  TrainController->LogEvent("ExitPrefDirButtonClick");
2118  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
2119  Level1Mode = BaseMode;
2120  SetLevel1Mode(6);
2121  Utilities->CallLogPop(1554);
2122  }
2123  catch(const Exception &e)
2124  {
2125  ErrorLog(133, e.Message);
2126  }
2127 }
2128 
2129 // ---------------------------------------------------------------------------
2130 // Operate Railway Interface
2131 // ---------------------------------------------------------------------------
2132 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
2133 {
2134  try
2135  {
2136  TrainController->LogEvent("OperateRailwayMenuItemClick");
2137  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
2138  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
2139  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
2140  Level1Mode = OperMode;
2141  SetLevel1Mode(7);
2142  Utilities->CallLogPop(26);
2143  }
2144  catch(const Exception &e)
2145  {
2146  ErrorLog(12, e.Message);
2147  }
2148 }
2149 
2150 // ---------------------------------------------------------------------------
2151 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
2152 {
2153  try
2154  {
2155  TrainController->LogEvent("StartOperationButtonClick");
2156  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
2158  {
2160  SetLevel2OperMode(0);
2161  }
2162  else
2163  {
2165  SetLevel2OperMode(1);
2166  }
2167  Utilities->CallLogPop(1175);
2168  }
2169  catch(const Exception &e)
2170  {
2171  ErrorLog(37, e.Message);
2172  }
2173 }
2174 
2175 // ---------------------------------------------------------------------------
2176 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
2177 // must have PrefDirs to be available
2178 {
2179  try
2180  {
2181  TrainController->LogEvent("AutoSigsButtonClick");
2182  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
2183  AutoSigsFlag = true;
2184  PreferredRoute = true;
2185  ConsecSignalsRoute = true;
2186 
2187  AutoSigsButton->Enabled = false;
2188  SigPrefConsecButton->Enabled = true;
2189  SigPrefNonConsecButton->Enabled = true;
2190  UnrestrictedButton->Enabled = true;
2191 
2192  InfoPanel->Visible = true;
2193  if(Level2OperMode == PreStart)
2194  {
2195  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2196  }
2197  else
2198  {
2199  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2200  }
2201  InfoCaptionStore = InfoPanel->Caption;
2202  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2203  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2204  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2206  Utilities->CallLogPop(28);
2207  }
2208  catch(const Exception &e)
2209  {
2210  ErrorLog(14, e.Message);
2211  }
2212 }
2213 
2214 // ---------------------------------------------------------------------------
2215 
2216 void __fastcall TInterface::SigPrefConsecButtonClick(TObject *Sender)
2217 // must have PrefDirs to be available
2218 {
2219  try
2220  {
2221  TrainController->LogEvent("SigPrefButtonClick");
2222  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2223  AutoSigsFlag = false;
2224  PreferredRoute = true;
2225  ConsecSignalsRoute = true;
2226 
2227  AutoSigsButton->Enabled = true;
2228  SigPrefConsecButton->Enabled = false;
2229  SigPrefNonConsecButton->Enabled = true;
2230  UnrestrictedButton->Enabled = true;
2231 
2232  InfoPanel->Visible = true;
2233  if(Level2OperMode == PreStart)
2234  {
2235  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2236  }
2237  else
2238  {
2239  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2240  }
2241  InfoCaptionStore = InfoPanel->Caption;
2242  AutoRouteStartMarker->PlotOriginal(43, Display); // if overlay not plotted will ignore
2243  SigRouteStartMarker->PlotOriginal(44, Display); // if overlay not plotted will ignore
2244  NonSigRouteStartMarker->PlotOriginal(45, Display); // if overlay not plotted will ignore
2246  Utilities->CallLogPop(2265);
2247  }
2248  catch(const Exception &e)
2249  {
2250  ErrorLog(221, e.Message);
2251  }
2252 }
2253 
2254 // ---------------------------------------------------------------------------
2255 
2256 void __fastcall TInterface::SigPrefNonConsecButtonClick(TObject *Sender)
2257 // must have PrefDirs to be available
2258 {
2259  try
2260  {
2261  TrainController->LogEvent("SigPrefButtonClick");
2262  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2263  AutoSigsFlag = false;
2264  PreferredRoute = true;
2265  ConsecSignalsRoute = false;
2266 
2267  AutoSigsButton->Enabled = true;
2268  SigPrefConsecButton->Enabled = true;
2269  SigPrefNonConsecButton->Enabled = false;
2270  UnrestrictedButton->Enabled = true;
2271 
2272  InfoPanel->Visible = true;
2273  if(Level2OperMode == PreStart)
2274  {
2275  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2276  }
2277  else
2278  {
2279  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2280  }
2281  InfoCaptionStore = InfoPanel->Caption;
2282  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2283  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2284  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2286  Utilities->CallLogPop(29);
2287  }
2288  catch(const Exception &e)
2289  {
2290  ErrorLog(15, e.Message);
2291  }
2292 }
2293 
2294 // ---------------------------------------------------------------------------
2295 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2296 {
2297  try
2298  {
2299  TrainController->LogEvent("NoSigNonPrefButtonClick");
2300  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2301  AutoSigsFlag = false;
2302  PreferredRoute = false;
2303  ConsecSignalsRoute = false;
2304  if(EveryPrefDir->PrefDirSize() > 0)
2305  {
2306  AutoSigsButton->Enabled = true;
2307  SigPrefConsecButton->Enabled = true;
2308  SigPrefNonConsecButton->Enabled = true;
2309  UnrestrictedButton->Enabled = false;
2310  }
2311  else
2312  {
2313  AutoSigsButton->Enabled = false;
2314  SigPrefConsecButton->Enabled = false;
2315  SigPrefNonConsecButton->Enabled = false;
2316  UnrestrictedButton->Enabled = false;
2317  }
2318  InfoPanel->Visible = true;
2319  if(Level2OperMode == PreStart)
2320  {
2321  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2322  }
2323  else
2324  {
2325  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2326  }
2327  InfoCaptionStore = InfoPanel->Caption;
2328  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2329  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2330  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2332  Utilities->CallLogPop(30);
2333  }
2334  catch(const Exception &e)
2335  {
2336  ErrorLog(16, e.Message);
2337  }
2338 }
2339 
2340 // ---------------------------------------------------------------------------
2341 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2342 {
2343  try
2344  {
2345  TrainController->LogEvent("RouteCancelButtonClick");
2346  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2347  RouteCancelFlag = true;
2348  InfoPanel->Visible = true;
2349  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2350  RouteCancelButton->Enabled = false;
2351  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2352  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2353  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2354  Utilities->CallLogPop(1176);
2355  }
2356  catch(const Exception &e)
2357  {
2358  ErrorLog(35, e.Message);
2359  }
2360 }
2361 
2362 // ---------------------------------------------------------------------------
2363 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2364 {
2365  try
2366  {
2367  TrainController->LogEvent("PerformanceLogButtonClick");
2368  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2370  {
2371  ShowPerformancePanel = true;
2372  PerformancePanel->Visible = true;
2373  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2374  }
2375  else
2376  {
2377  ShowPerformancePanel = false;
2378  PerformancePanel->Visible = false;
2379  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2380  }
2381  Utilities->CallLogPop(1177);
2382  }
2383  catch(const Exception &e)
2384  {
2385  ErrorLog(36, e.Message);
2386  }
2387 }
2388 // ---------------------------------------------------------------------------
2389 
2390 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2391 {
2392  try
2393  {
2394  TrainController->LogEvent("ExitOperationButtonClick");
2395  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2397  {
2398  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2399  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2401  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2402  TrainController->BaseTime = TDateTime::CurrentDateTime();
2404  if(button == IDNO)
2405  {
2406  Utilities->CallLogPop(751);
2407  return;
2408  }
2409  }
2410  Track->ResetSignals(1);
2411  Track->ResetPoints(1);
2412  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2413  Utilities->PerformanceFile.close();
2416  RouteMode = None;
2417  PreferredRoute = true; // default starting conditions
2418  ConsecSignalsRoute = true; // default starting conditions
2420  ShowPerformancePanel = false;
2421  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2422  ShowOperatorActionPanel = false; // new at v2.2.0
2423  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2424  PerformanceLogBox->Lines->Clear();
2425  PerformancePanel->Visible = false;
2426  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2427  PerformancePanel->Left = MainScreen->Left;
2428 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2429  OAListBox->Clear();
2430  OperatorActionPanel->Visible = false;
2431  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2432  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
2433  ;
2435  AllRoutes->LockedRouteVector.clear();
2436  Level1Mode = BaseMode;
2437  SetLevel1Mode(8); // calls Clearand...
2438  Utilities->CallLogPop(1555);
2439  }
2440  catch(const Exception &e)
2441  {
2442  ErrorLog(13, e.Message);
2443  }
2444 }
2445 
2446 // ---------------------------------------------------------------------------
2447 // Menu Interface (for items not already covered above)
2448 // ---------------------------------------------------------------------------
2449 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2450 {
2451  try
2452  {
2453  TrainController->LogEvent("LoadRailwayMenuItemClick");
2454  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2455  if(!ClearEverything(1))
2456  {
2457  Utilities->CallLogPop(1139);
2458  return;
2459  }
2460  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2461  // changed at v2.0.0 (Embarcadero change) to show all files together
2462  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2463  if(LoadRailwayDialog->Execute())
2464  {
2465  if(LoadRailwayDialog->InitialDir != TPath::GetDirectoryName(LoadRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
2466  {
2467  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2468  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2469  }
2470  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2471  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2472  }
2473  // else ShowMessage("Load Aborted"); drop this
2474  // Display->Update(); //display updated in ClearandRebuildRailway
2475  Track->CalcHLocMinEtc(9);
2476  Level1Mode = BaseMode;
2479  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2480  Utilities->CallLogPop(31);
2481  }
2482  catch(const Exception &e)
2483  {
2484  ErrorLog(17, e.Message);
2485  }
2486 }
2487 // ---------------------------------------------------------------------------
2488 
2489 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2490 {
2491  // display of the loaded railway covered in the calling routine
2492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2493  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2494  {
2495  Screen->Cursor = TCursor(-11); // Hourglass;
2496  std::ifstream VecFile(LoadFileName.c_str());
2497  if(!(VecFile.fail()))
2498  {
2499  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2500  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2501  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2502  bool GraphicsFollow = false;
2503  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2504 // load track elements
2505  Track->LoadTrack(1, VecFile, GraphicsFollow);
2506 // load text elements
2507  TextHandler->LoadText(0, VecFile);
2508 // load PrefDir elements
2509  EveryPrefDir->LoadPrefDir(0, VecFile);
2510  if(GraphicsFollow)
2511  {
2512 // load user graphics
2513  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2514  }
2515  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2516  VecFile.close();
2517  Display->DisplayOffsetHHome = TempOffsetHHome;
2518  Display->DisplayOffsetVHome = TempOffsetVHome;
2520 
2521  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2522  TempFont->Style.Clear();
2523  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2524  TempFont->Size = 10;
2525  TempFont->Color = clB0G0R0;
2526  TempFont->Charset = (TFontCharset)(0);
2527  MainScreen->Canvas->Font->Assign(TempFont);
2528  delete TempFont;
2529 
2530 // calculate starting zoomed out offset values - same as when zoom out button clicked
2531  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2532 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2533  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2534  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2535  if((LeftExcess > 0) && (RightExcess > 0))
2536  {
2537  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2538  }
2539  else if((LeftExcess > 0) && (RightExcess <= 0))
2540  {
2541  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2542  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2543  }
2544  else if((LeftExcess <= 0) && (RightExcess > 0))
2545  {
2546  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2547  }
2548  else
2549  {
2550  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2551 
2552  }
2553  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2554  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2555  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2556  if((TopExcess > 0) && (BotExcess > 0))
2557  {
2558  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2559  }
2560  else if((TopExcess > 0) && (BotExcess <= 0))
2561  {
2562  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2563  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2564  }
2565  else if((TopExcess <= 0) && (BotExcess > 0))
2566  {
2567  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2568  }
2569  else
2570  {
2571  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2572  }
2573 // all above same as when zoom out button clicked
2574  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2576 
2577  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2578  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2579  {
2580  Track->DuplicatedLocationName(1, true);
2581  char LastChar = SavedFileName[SavedFileName.Length()];
2582  if((LastChar == 'y') || (LastChar == 'Y'))
2583  {
2584  if(!(Track->IsReadyForOperation(false)))
2585  {
2586  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2587  SavedFileName = "";
2588  RlyFile = false;
2589  RailwayTitle = "";
2590  TimetableTitle = "";
2591  SetCaption(5);
2592  Track->CalcHLocMinEtc(1);
2593  Screen->Cursor = TCursor(-2); // Arrow
2594  Level1Mode = BaseMode;
2595  SetLevel1Mode(9);
2596  Utilities->CallLogPop(1136);
2597  return;
2598  }
2599  else
2600  {
2601  RlyFile = true;
2602  }
2603  }
2604  else
2605  {
2606  RlyFile = false;
2607  }
2608  }
2609  else
2610  {
2611  RlyFile = false;
2612  }
2613  FileChangedFlag = false;
2614  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2615  {
2616  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2617  {
2618  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2619  TimetableTitle = "";
2620  SetCaption(6);
2621  break;
2622  }
2623  }
2624  } // if(VecFile)
2625  else
2626  {
2627  ShowMessage("File open failed prior to load");
2628  }
2629  Screen->Cursor = TCursor(-2); // Arrow
2630  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2631  else
2632  {
2633  ShowMessage("File integrity check failed - unable to load " + LoadFileName + ". Please check that the file exists and is spelled correctly.");
2634  }
2635  Utilities->CallLogPop(1774);
2636 }
2637 
2638 // ---------------------------------------------------------------------------
2639 
2640 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2641 {
2642 // save under existing name
2643 // no need to alter RlyFile for saving under existing name
2644 
2645  try
2646  {
2647  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2648  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2649  Screen->Cursor = TCursor(-11); // Hourglass;
2650  std::ofstream VecFile(SavedFileName.c_str());
2651  if(!(VecFile.fail()))
2652  {
2656  // save track elements
2657  if(Track->UserGraphicVector.empty())
2658  {
2659  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2660  }
2661  else
2662  {
2663  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2664  }
2665  // save text elements
2666  TextHandler->SaveText(0, VecFile);
2667  // save PrefDir elements
2668  EveryPrefDir->SavePrefDirVector(0, VecFile);
2669  if(!Track->UserGraphicVector.empty())
2670  {
2671  // save user graphics
2672  Track->SaveUserGraphics(0, VecFile);
2673  }
2674  FileChangedFlag = false;
2675  VecFile.close();
2676  }
2677  else
2678  {
2679  ShowMessage("File open failed prior to save");
2680  }
2681  Screen->Cursor = TCursor(-2); // Arrow
2682  Level1Mode = BaseMode;
2683  SetLevel1Mode(12); // to disable the save option
2684  Utilities->CallLogPop(1178);
2685  }
2686  catch(const Exception &e)
2687  {
2688  ErrorLog(135, e.Message);
2689  }
2690 }
2691 
2692 // ---------------------------------------------------------------------------
2693 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2694 {
2695  try
2696  {
2697  TrainController->LogEvent("SaveAsMenuItemClick");
2698  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2699  SaveAsSubroutine(0);
2700  Utilities->CallLogPop(32);
2701  }
2702  catch(const Exception &e)
2703  {
2704  ErrorLog(18, e.Message);
2705  }
2706 }
2707 
2708 // ---------------------------------------------------------------------------
2709 
2710 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2711 {
2712  // need to stop clock in case invoke during operation
2713  try
2714  {
2715  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2716  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2717  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2718  {
2719  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2720  Utilities->CallLogPop(1695);
2721  return;
2722  }
2723  Screen->Cursor = TCursor(-11); // Hourglass;
2724  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2726  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2727  // format "16/06/2009 20:55:17"
2728  // avoid characters in filename:= / \ : * ? " < > |
2729  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2730  AnsiString ShortName = "";
2731  for(int x = ImageFileName.Length(); x > 0; x--)
2732  {
2733  if(ImageFileName[x] == '\\')
2734  {
2735  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2736  break;
2737  }
2738  }
2739  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2740  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2741  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2742 
2743  int HPosMin = Track->GetHLocMin() * 16;
2744  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2745  int VPosMin = Track->GetVLocMin() * 16;
2746  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2747  RailwayImage->Width = HPosMax - HPosMin;
2748  RailwayImage->Height = VPosMax - VPosMin;
2749 
2750  // need to check if there is any text that extends past HPosMax or below VPosMax
2751  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2752  if(!TextHandler->TextVector.empty())
2753  {
2754  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2755  {
2756  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2757  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2758  if(NewWidth > RailwayImage->Width)
2759  {
2760  RailwayImage->Width = NewWidth;
2761  }
2762  if(NewHeight > RailwayImage->Height)
2763  {
2764  RailwayImage->Height = NewHeight;
2765  }
2766  }
2767  }
2768  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2769  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2770  RailwayImage->Canvas->FillRect(Rect);
2771 
2772  // write graphics first so text & track overwrite
2773  Track->WriteGraphicsToImage(0, RailwayImage);
2774  // then write text so track overwrites
2775  TextHandler->WriteTextToImage(0, RailwayImage);
2776  Track->WriteTrackToImage(0, RailwayImage);
2777 
2778  RailwayImage->SaveToFile(ImageFileName);
2779  delete RailwayImage;
2780  TrainController->BaseTime = TDateTime::CurrentDateTime();
2782  Screen->Cursor = TCursor(-2); // Arrow
2783  Utilities->CallLogPop(1535);
2784  }
2785  catch(const Exception &e) //non error catch
2786  {
2787  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2788  {
2789  Screen->Cursor = TCursor(-2); // Arrow;
2790  UnicodeString MessageStr = "Insufficient memory available to store this image";
2791  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2792  Utilities->CallLogPop(2297);
2793  }
2794  else
2795  {
2796  ErrorLog(42, e.Message);
2797  }
2798  }
2799 }
2800 
2801 // ---------------------------------------------------------------------------
2802 
2803 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2804 {
2805  // need to stop clock in case invoke during operation
2806  try
2807  {
2808  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2809  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2810  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2811  {
2812  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2813  Utilities->CallLogPop(1696);
2814  return;
2815  }
2816  Screen->Cursor = TCursor(-11); // Hourglass;
2817  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2819  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2820  // format "16/06/2009 20:55:17"
2821  // avoid characters in filename:= / \ : * ? " < > |
2822  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2823  AnsiString ShortName = "";
2824  for(int x = ImageFileName.Length(); x > 0; x--)
2825  {
2826  if(ImageFileName[x] == '\\')
2827  {
2828  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2829  break;
2830  }
2831  }
2832  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2833  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2834  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2835  int HPosMin = Track->GetHLocMin() * 16;
2836  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2837  int VPosMin = Track->GetVLocMin() * 16;
2838  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2839  RailwayImage->Width = HPosMax - HPosMin;
2840  RailwayImage->Height = VPosMax - VPosMin;
2841 
2842  // need to check if there is any text that extends past HPosMax or below VPosMax
2843  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2844  if(!TextHandler->TextVector.empty())
2845  {
2846  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2847  {
2848  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2849  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2850  if(NewWidth > RailwayImage->Width)
2851  {
2852  RailwayImage->Width = NewWidth;
2853  }
2854  if(NewHeight > RailwayImage->Height)
2855  {
2856  RailwayImage->Height = NewHeight;
2857  }
2858  }
2859  }
2860  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2861  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2862  RailwayImage->Canvas->FillRect(Rect);
2863 
2864  // write the grid first so all else on top
2865  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2866  {
2867  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2868  {
2869  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2870  }
2871  }
2872  // write graphics next so text & track overwrite
2873  Track->WriteGraphicsToImage(1, RailwayImage);
2874  // then write text so track overwrites
2875  TextHandler->WriteTextToImage(1, RailwayImage);
2876  Track->WriteTrackToImage(1, RailwayImage);
2877  RailwayImage->SaveToFile(ImageFileName);
2878  delete RailwayImage;
2879  TrainController->BaseTime = TDateTime::CurrentDateTime();
2881  Screen->Cursor = TCursor(-2); // Arrow
2882  Utilities->CallLogPop(1536);
2883  }
2884  catch(const Exception &e) //non error catch
2885  {
2886  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2887  {
2888  Screen->Cursor = TCursor(-2); // Arrow;
2889  UnicodeString MessageStr = "Insufficient memory available to store this image";
2890  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2891  Utilities->CallLogPop(2298);
2892  }
2893  else
2894  {
2895  ErrorLog(43, e.Message);
2896  }
2897  }
2898 }
2899 // ---------------------------------------------------------------------------
2900 
2901 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2902 {
2903  // need to stop clock in case invoke during operation
2904  try
2905  {
2906  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2907  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2908  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2909  {
2910  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2911  Utilities->CallLogPop(1697);
2912  return;
2913  }
2914  Screen->Cursor = TCursor(-11); // Hourglass;
2915  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2917  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2918  // format "16/06/2009 20:55:17"
2919  // avoid characters in filename:= / \ : * ? " < > |
2920  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2921  AnsiString ShortName = "";
2922  for(int x = ImageFileName.Length(); x > 0; x--)
2923  {
2924  if(ImageFileName[x] == '\\')
2925  {
2926  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2927  break;
2928  }
2929  }
2930  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2931  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2932  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2933  int HPosMin = Track->GetHLocMin() * 16;
2934  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2935  int VPosMin = Track->GetVLocMin() * 16;
2936  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2937  RailwayImage->Width = HPosMax - HPosMin;
2938  RailwayImage->Height = VPosMax - VPosMin;
2939 
2940  // need to check if there is any text that extends past HPosMax or below VPosMax
2941  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2942  if(!TextHandler->TextVector.empty())
2943  {
2944  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2945  {
2946  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2947  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2948  if(NewWidth > RailwayImage->Width)
2949  {
2950  RailwayImage->Width = NewWidth;
2951  }
2952  if(NewHeight > RailwayImage->Height)
2953  {
2954  RailwayImage->Height = NewHeight;
2955  }
2956  }
2957  }
2958  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2959  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2960  RailwayImage->Canvas->FillRect(Rect);
2961 
2962  // write graphics first so text & track overwrite
2963  Track->WriteGraphicsToImage(2, RailwayImage);
2964  // then write text so track overwrites
2965  TextHandler->WriteTextToImage(2, RailwayImage);
2966  Track->WriteTrackToImage(2, RailwayImage);
2967  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2968  RailwayImage->SaveToFile(ImageFileName);
2969  delete RailwayImage;
2970  TrainController->BaseTime = TDateTime::CurrentDateTime();
2972  Screen->Cursor = TCursor(-2); // Arrow
2973  Utilities->CallLogPop(1566);
2974  }
2975  catch(const Exception &e) //non error catch
2976  {
2977  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2978  {
2979  Screen->Cursor = TCursor(-2); // Arrow;
2980  UnicodeString MessageStr = "Insufficient memory available to store this image";
2981  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2982  Utilities->CallLogPop(2299);
2983  }
2984  else
2985  {
2986  ErrorLog(45, e.Message);
2987  }
2988  }
2989 }
2990 // ---------------------------------------------------------------------------
2991 
2992 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2993 {
2994  // need to stop clock
2995  try
2996  {
2997  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2998  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2999  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
3000  {
3001  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
3002  Utilities->CallLogPop(1702);
3003  return;
3004  }
3005  Screen->Cursor = TCursor(-11); // Hourglass;
3006  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
3008 
3009  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
3010  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
3011  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
3012  // format "16/06/2009 20:55:17"
3013  // avoid characters in filename:= / \ : * ? " < > |
3014  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
3015  "; " + TimetableTitle + ".bmp";
3016  AnsiString ShortName = "";
3017  for(int x = ImageFileName.Length(); x > 0; x--)
3018  {
3019  if(ImageFileName[x] == '\\')
3020  {
3021  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
3022  break;
3023  }
3024  }
3025  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
3026  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
3027  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
3028  int HPosMin = Track->GetHLocMin() * 16;
3029  int HPosMax = (Track->GetHLocMax() + 1) * 16;
3030  int VPosMin = Track->GetVLocMin() * 16;
3031  int VPosMax = (Track->GetVLocMax() + 1) * 16;
3032  RailwayImage->Width = HPosMax - HPosMin;
3033  RailwayImage->Height = VPosMax - VPosMin;
3034 
3035  // need to check if there is any text that extends past HPosMax or below VPosMax
3036  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
3037  if(!TextHandler->TextVector.empty())
3038  {
3039  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
3040  {
3041  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
3042  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
3043  if(NewWidth > RailwayImage->Width)
3044  {
3045  RailwayImage->Width = NewWidth;
3046  }
3047  if(NewHeight > RailwayImage->Height)
3048  {
3049  RailwayImage->Height = NewHeight;
3050  }
3051  }
3052  }
3053  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
3054  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
3055  RailwayImage->Canvas->FillRect(Rect);
3056 
3057  // write graphics first so text & track overwrite
3058  Track->WriteGraphicsToImage(3, RailwayImage);
3059  // then write text so track overwrites
3060  TextHandler->WriteTextToImage(3, RailwayImage);
3061  Track->WriteOperatingTrackToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
3062  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
3063 // add any locked route markers
3064  if(!AllRoutes->LockedRouteVector.empty())
3065  {
3066  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
3067  {
3068  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
3069  int x = Route.PrefDirSize() - 1;
3070  bool BreakFlag = false;
3071  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
3072  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
3073  {
3074  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3075  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3076  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
3077  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
3078  {
3079  BreakFlag = true;
3080  break; // train removed earlier element from route so stop here
3081  }
3082  x--;
3083  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
3084  }
3085  if(!BreakFlag)
3086  {
3087  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
3088  {
3089  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
3090  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
3091  }
3092  }
3093  }
3094  }
3095  TrainController->WriteTrainsToImage(0, RailwayImage);
3096  RailwayImage->SaveToFile(ImageFileName);
3097  delete RailwayImage;
3098  TrainController->BaseTime = TDateTime::CurrentDateTime();
3100  Screen->Cursor = TCursor(-2); // Arrow
3101  Utilities->CallLogPop(1703);
3102  }
3103  catch(const Exception &e) //non error catch
3104  {
3105  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
3106  {
3107  Screen->Cursor = TCursor(-2); // Arrow;
3108  UnicodeString MessageStr = "Insufficient memory available to store this image";
3109  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
3110  Utilities->CallLogPop(2300);
3111  }
3112  else
3113  {
3114  ErrorLog(113, e.Message); // NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
3115  }
3116  }
3117 }
3118 
3119 // ---------------------------------------------------------------------------
3120 
3121 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
3122 {
3123 //
3124  try
3125  {
3126  TrainController->LogEvent("SaveHeaderMenu1Click");
3127  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
3128  if(Sender == SaveSessionButton)
3129  {
3130  SaveSessionFlag = true;
3131  }
3132  else if(SavedFileName == "") // use 'Save As' function
3133  {
3134  SaveAsSubroutine(1);
3135  }
3136  else // ordinary save
3137  {
3138  Screen->Cursor = TCursor(-11); // Hourglass;
3139  std::ofstream VecFile(SavedFileName.c_str());
3140  if(!(VecFile.fail()))
3141  {
3145  // save track elements
3146  if(Track->UserGraphicVector.empty())
3147  {
3148  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
3149  }
3150  else
3151  {
3152  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
3153  }
3154  // save text elements
3155  TextHandler->SaveText(5, VecFile);
3156  // save PrefDir elements
3157  EveryPrefDir->SavePrefDirVector(8, VecFile);
3158  if(!Track->UserGraphicVector.empty())
3159  {
3160  // save user graphics
3161  Track->SaveUserGraphics(1, VecFile);
3162  }
3163  FileChangedFlag = false;
3164  VecFile.close();
3165  }
3166  else
3167  {
3168  ShowMessage("Railway failed to save - can't open file");
3169  }
3170  Screen->Cursor = TCursor(-2); // Arrow
3171  }
3172  Utilities->CallLogPop(1552);
3173  }
3174  catch(const Exception &e)
3175  {
3176  ErrorLog(44, e.Message);
3177  }
3178 }
3179 
3180 // ---------------------------------------------------------------------------
3181 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
3182 {
3183  try
3184  {
3185  TrainController->LogEvent("LoadSessionMenuItemClick");
3186  LoadSessionFlag = true; // load session within ClockTimer2
3187  }
3188  catch(const Exception &e)
3189  {
3190  ErrorLog(136, e.Message);
3191  }
3192 }
3193 
3194 // ---------------------------------------------------------------------------
3195 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
3196 {
3197  try
3198  {
3199  TrainController->LogEvent("ClearAllMenuItemClick");
3200  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
3201  if(ClearEverything(2))
3202  {
3203  ;
3204  } // no change in action on result
3205 
3206  Level1Mode = BaseMode;
3207  SetLevel1Mode(126);
3208  Utilities->CallLogPop(1179);
3209  }
3210  catch(const Exception &e)
3211  {
3212  ErrorLog(137, e.Message);
3213  }
3214 }
3215 
3216 // ---------------------------------------------------------------------------
3217 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
3218 {
3219  // no need to stop clock as can't be called when railway operating
3220  try
3221  {
3222  TrainController->LogEvent("ExportTTMenuItemClick");
3223  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
3224  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
3225  {
3226  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
3227  Utilities->CallLogPop(1699);
3228  return;
3229  }
3230 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
3231 // the message instead, but reset here afterwards
3232  // no need to stop clock as can't select this if operating
3234  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
3235  Utilities->CallLogPop(1573);
3236  }
3237  catch(const Exception &e)
3238  {
3239  ErrorLog(138, e.Message);
3240  }
3241 }
3242 // ---------------------------------------------------------------------------
3243 // Timetable editing functions
3244 
3245 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
3246  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
3247  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
3248  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
3249  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
3250 
3251  CR & LF review:
3252  These cause problems by the way that different subroutines handle them.
3253 
3254  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
3255 
3256  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
3257  (a) n-1 characters are stored + '\0' after the n-1 characters;
3258  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
3259  precedes the CRLF in the stream; and
3260  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
3261  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
3262 
3263  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
3264  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
3265 
3266 */
3267 // ---------------------------------------------------------------------------
3268 
3269 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
3270 {
3271  try
3272  {
3273  TrainController->LogEvent("CreateTimetableMenuItemClick");
3274  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
3275  CreateEditTTFileName = "";
3276  TimetableEditVector.clear();
3277  TimetableEditPanel->Visible = true;
3278  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3279  HighlightPanel->Visible = false;
3280  TimetablePanel->Visible = true;
3281  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3282  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3283  OneEntryTimetableMemo->Clear();
3284  AllEntriesTTListBox->Clear();
3285  TTStartTimeBox->Text = "";
3286  AddSubMinsBox->Text = "";
3288  LocationNameComboBox->Clear();
3289  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
3290  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
3291  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3292  TimetableChangedFlag = false;
3293  TimetableValidFlag = false;
3294  TTEntryChangedFlag = false;
3296  AZOrderButton->Caption = AnsiString("A-Z Order");
3297  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3298  CopiedEntryFlag = false;
3299  NewEntryInPreparationFlag = false;
3300  CopiedEntryStr = "";
3301  TEVPtr = 0;
3303  TTFirstServicePtr = 0;
3304  TTLastServicePtr = 0; // all set to null to begin with
3305 
3306 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3307  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3309  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3310  {
3312  == Track->ContinuationNameMap.end())
3313  {
3314  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3315  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1038, x).ActiveTrackElementName;
3316  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3317  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3318  }
3319  }
3321  if(!(Track->ActiveTrackElementNameMap.empty()))
3322  {
3323  LocationNameComboBox->Text = "Location names";
3324 // new version at beta v0.2b
3326  ATENIT++)
3327  {
3328  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3329  // continuations as well as other track will be included - earlier version
3330  // would have excluded them
3331  }
3332 
3333 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3334  locations
3335  TStringList *StringList = new TStringList;
3336  StringList->Clear();//probably already empty but help file doesn't say so
3337  StringList->Sorted = false;//for now
3338  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3339  {
3340  NewKey = LNMIT->first;
3341  if(OldKey != NewKey)//only add new values
3342  {
3343  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3344  {
3345  StringList->Add(NewKey);
3346  OldKey = NewKey;
3347  }
3348  }
3349  }
3350  StringList->Sort();
3351  for(int x=0;x<StringList->Count;x++)
3352  {
3353  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3354  }
3355  delete StringList;
3356 */
3357  }
3358  else
3359  {
3360  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3361  }
3363  SetLevel1Mode(82);
3364  Utilities->CallLogPop(1595);
3365  }
3366  catch(const Exception &e)
3367  {
3368  ErrorLog(47, e.Message);
3369  }
3370 }
3371 
3372 // ---------------------------------------------------------------------------
3373 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3374 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3375  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3376 */
3377 {
3378  try
3379  {
3380  TrainController->LogEvent("EditTimetableMenuItemClick");
3381  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3382  SigImagePanel->Visible = false; // stop panel showing while waiting for name entry
3383  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3384  CreateEditTTFileName = "";
3385  TimetableEditVector.clear();
3386  TimetableEditPanel->Visible = true;
3387  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3388  HighlightPanel->Visible = false;
3389  TimetablePanel->Visible = true;
3390  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3391  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3392  OneEntryTimetableMemo->Clear();
3393  AllEntriesTTListBox->Clear();
3394  TTStartTimeBox->Text = "";
3395  AddSubMinsBox->Text = "";
3397  LocationNameComboBox->Clear();
3398  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3399  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3400  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3401  TEVPtr = 0;
3403  TTFirstServicePtr = 0;
3404  TTLastServicePtr = 0; // all set to null to begin with
3405  if(TimetableDialog->Execute())
3406  {
3407  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
3408  {
3409  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3410  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3411  }
3412  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3413  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3414  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3415  if(TTBLFile.is_open())
3416  {
3417  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3418  char c;
3419  while(!TTBLFile.eof())
3420  {
3421  TTBLFile.get(c);
3422  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3423  {
3424  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3425  TTBLFile.close();
3426  Utilities->CallLogPop(1612);
3427  return;
3428  }
3429  }
3430  TTBLFile.close();
3431  }
3432  else
3433  {
3434  ShowMessage("Failed to open timetable file " + CreateEditTTFileName + ", make sure it's spelled correctly, it exists and isn't open in another application");
3435  Utilities->CallLogPop(1597);
3436  return;
3437  }
3438  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3439  Delay(4, 100); // 100mSec delay between closing & re-opening file
3440  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3441  if(TTBLFile.is_open())
3442  {
3443  TTBLFile.clear(); // to clear eofbit from last read
3444  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3445  TimetableChangedFlag = false;
3446  TimetableValidFlag = false;
3447  TTEntryChangedFlag = false;
3449  AZOrderButton->Caption = AnsiString("A-Z Order");
3450  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3451  NewEntryInPreparationFlag = false;
3452  CopiedEntryStr = "";
3453  CopiedEntryFlag = false;
3454 // CreateEditTTFileName = TimetableDialog->FileName;
3455  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3456  {
3457  if(CreateEditTTFileName[x] == '\\')
3458  {
3459  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3460  break;
3461  }
3462  }
3463  char *TimetableEntryString = new char[10000];
3464  while(true)
3465  {
3466  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3467  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3468  {
3469  // may still have eof even if read a line, and
3470  // if so need to process it
3471  break;
3472  }
3473  AnsiString OneLine(TimetableEntryString);
3474  TimetableEditVector.push_back(OneLine);
3475  }
3476  TTBLFile.close();
3477  delete[]TimetableEntryString;
3478  // here with TimetableEditVector compiled
3479  }
3480  else
3481  {
3482  ShowMessage("Failed to open timetable file " + CreateEditTTFileName + ", make sure it's spelled correctly, it exists and isn't open in another application");
3483  Utilities->CallLogPop(1654);
3484  return;
3485  }
3486  }
3487  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3488  {
3489  CreateEditTTFileName = "";
3490 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3491  CreateEditTTTitle = ""; // as above
3492  Level1Mode = BaseMode;
3493  SetLevel1Mode(132);
3494  Utilities->CallLogPop(1633);
3495  return;
3496  }
3498  if(TimetableEditVector.empty())
3499  {
3501  SetLevel1Mode(89);
3502  Utilities->CallLogPop(1614);
3503  return;
3504  }
3505 // all now set where can be
3507 
3508 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3509  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3511  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3512  {
3514  == Track->ContinuationNameMap.end())
3515  {
3516  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3517  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1041, x).ActiveTrackElementName;
3518  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3519  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3520  }
3521  }
3523  if(!(Track->ActiveTrackElementNameMap.empty()))
3524  {
3525  LocationNameComboBox->Text = "Location names";
3526 // new version for beta v0.2b
3528  ATENIT++)
3529  {
3530  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3531  // continuations as well as other track will be included - earlier version
3532  // would have excluded them
3533  }
3534  }
3535  else
3536  {
3537  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3538  }
3540  SetLevel1Mode(83);
3541  Utilities->CallLogPop(1596);
3542  }
3543  catch(const Exception &e)
3544  {
3545  ErrorLog(48, e.Message);
3546  }
3547 }
3548 // ---------------------------------------------------------------------------
3549 
3550 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3551 {
3552  try
3553  {
3554  TrainController->LogEvent("ShowHideTTButtonClick");
3555  if(TimetableEditPanel->Visible)
3556  {
3557  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3558  TimetableEditPanel->Visible = false;
3559  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
3560  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3561 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3562  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3563  }
3564  else
3565  {
3566  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3567  TimetableEditPanel->Visible = true;
3568  TrainController->TTEditPanelVisible = true; // added at v2.6.0 for two location message
3569  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3571  SetLevel1Mode(124);
3572  }
3573  }
3574  catch(const Exception &e)
3575  {
3576  ErrorLog(139, e.Message);
3577  }
3578 }
3579 // ---------------------------------------------------------------------------
3580 
3581 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3582 {
3583  try
3584  {
3585  TrainController->LogEvent("NextTTEntryButtonClick");
3586  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3587  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3588  {
3589  Utilities->CallLogPop(1683);
3590  return;
3591  }
3592  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3593  {
3595  }
3596  TTEntryChangedFlag = false;
3597  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3598  // position changing in AllEntriesTTListBox
3600  SetLevel1Mode(85);
3601  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3602  {
3604  }
3605  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3606  {
3607  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3608  }
3609  else
3610  {
3611  AllEntriesTTListBox->TopIndex = TopPos;
3612  }
3613  Utilities->CallLogPop(1605);
3614  }
3615  catch(const Exception &e)
3616  {
3617  ErrorLog(50, e.Message);
3618  }
3619 }
3620 
3621 // ---------------------------------------------------------------------------
3622 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3623 {
3624  try
3625  {
3626  TrainController->LogEvent("PreviousTTEntryButtonClick");
3627  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3628  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3629  {
3630  Utilities->CallLogPop(1684);
3631  return;
3632  }
3634  {
3636  }
3637  TTEntryChangedFlag = false;
3638  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3639  // position changing in AllEntriesTTListBox
3641  SetLevel1Mode(86);
3642  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3643  {
3645  }
3646  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3647  {
3648  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3649  }
3650  else
3651  {
3652  AllEntriesTTListBox->TopIndex = TopPos;
3653  }
3654  Utilities->CallLogPop(1607);
3655  }
3656  catch(const Exception &e)
3657  {
3658  ErrorLog(51, e.Message);
3659  }
3660 }
3661 
3662 // ---------------------------------------------------------------------------
3663 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3664 {
3665  try
3666  {
3667  TrainController->LogEvent("NewTTEntryButtonClick");
3668  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3669  OneEntryTimetableMemo->Clear();
3670  OneEntryTimetableMemo->SetFocus();
3673  SetLevel1Mode(103);
3674  Utilities->CallLogPop(1615);
3675  }
3676  catch(const Exception &e)
3677  {
3678  ErrorLog(52, e.Message);
3679  }
3680 }
3681 // ---------------------------------------------------------------------------
3682 
3683 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3684 {
3685  try
3686  {
3687  TrainController->LogEvent("AddMinsButtonClick");
3688  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3689  bool ValidFlag = true;
3690  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3691  {
3692  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3693  {
3694  ValidFlag = false;
3695  break;
3696  }
3697  }
3698  if(ValidFlag)
3699  {
3700  if(AddSubMinsBox->Text.ToInt() == 0)
3701  {
3702  ValidFlag = false;
3703  }
3704  }
3705  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3706  {
3707  Utilities->CallLogPop(1649);
3708  return;
3709  }
3710  TDateTime DummyTime;
3711  int AddMins = AddSubMinsBox->Text.ToInt();
3712  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3713  {
3714  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3715  {
3716  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3717  {
3718  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3719  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3720  Mins += AddMins;
3721  while(Mins >= 60)
3722  {
3723  Mins -= 60;
3724  Hrs++;
3725  }
3726  if(Hrs > 95)
3727  {
3728  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3729  Utilities->CallLogPop(1650);
3730  return;
3731  }
3732  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3733  if(Mins < 10)
3734  {
3735  MinsStr = "0" + MinsStr;
3736  }
3737  if(Hrs < 10)
3738  {
3739  HrsStr = "0" + HrsStr;
3740  }
3741  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3742  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3743  NewString += HrsStr + ':' + MinsStr;
3744  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3745  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3746  }
3747  }
3748  }
3749 
3750  OneEntryTimetableMemo->HideSelection = true;
3751  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3752  OneEntryTimetableMemo->SelLength = 0;
3753  TimetableValidFlag = false;
3754  TimetableChangedFlag = true;
3755  TTEntryChangedFlag = true;
3757  SetLevel1Mode(91);
3758  Utilities->CallLogPop(1617);
3759  }
3760  catch(const Exception &e)
3761  {
3762  ErrorLog(54, e.Message);
3763  }
3764 }
3765 // ---------------------------------------------------------------------------
3766 
3767 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3768 {
3769  try
3770  {
3771  TrainController->LogEvent("SubMinsButtonClick");
3772  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3773  bool ValidFlag = true;
3774  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3775  {
3776  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3777  {
3778  ValidFlag = false;
3779  break;
3780  }
3781  }
3782  if(ValidFlag)
3783  {
3784  if(AddSubMinsBox->Text.ToInt() == 0)
3785  {
3786  ValidFlag = false;
3787  }
3788  }
3789  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3790  {
3791  Utilities->CallLogPop(1659);
3792  return;
3793  }
3794  TDateTime DummyTime;
3795  int SubMins = AddSubMinsBox->Text.ToInt();
3796  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3797  {
3798  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3799  {
3800  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3801  {
3802  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3803  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3804  Mins -= SubMins;
3805  while(Mins < 0)
3806  {
3807  Mins += 60;
3808  Hrs--;
3809  }
3810  if(Hrs < 0)
3811  {
3812  ShowMessage("One or more times are now before 00:00, this is not permitted");
3813  Utilities->CallLogPop(1660);
3814  return;
3815  }
3816  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3817  if(Mins < 10)
3818  {
3819  MinsStr = "0" + MinsStr;
3820  }
3821  if(Hrs < 10)
3822  {
3823  HrsStr = "0" + HrsStr;
3824  }
3825  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3826  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3827  NewString += HrsStr + ':' + MinsStr;
3828  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3829  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3830  }
3831  }
3832  }
3833  OneEntryTimetableMemo->HideSelection = true;
3834  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3835  OneEntryTimetableMemo->SelLength = 0;
3836  TimetableValidFlag = false;
3837  TimetableChangedFlag = true;
3838  TTEntryChangedFlag = true;
3840  SetLevel1Mode(92);
3841  Utilities->CallLogPop(1618);
3842  }
3843  catch(const Exception &e)
3844  {
3845  ErrorLog(55, e.Message);
3846  }
3847 }
3848 // ---------------------------------------------------------------------------
3849 
3850 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3851 {
3852  try
3853  {
3854  TrainController->LogEvent("CopyTTEntryButtonClick");
3855  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3856  if(TTCurrentEntryPtr == 0)
3857  {
3858  Utilities->CallLogPop(1636);
3859  return;
3860  }
3862  CopiedEntryFlag = true;
3863  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3864  // position changing in AllEntriesTTListBox
3866  SetLevel1Mode(93);
3867  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3868  {
3870  }
3871  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3872  {
3873  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3874  }
3875  else
3876  {
3877  AllEntriesTTListBox->TopIndex = TopPos;
3878  }
3879  Utilities->CallLogPop(1619);
3880  }
3881  catch(const Exception &e)
3882  {
3883  ErrorLog(56, e.Message);
3884  }
3885 }
3886 // ---------------------------------------------------------------------------
3887 
3888 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3889 {
3890  try
3891  {
3892  TrainController->LogEvent("CutTTEntryButtonClick");
3893  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3894  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3895  {
3896  Utilities->CallLogPop(1674);
3897  return;
3898  }
3900  CopiedEntryFlag = true;
3901  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3902  // so use the position in the vector
3904 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3905 // pick up the start time if there is one
3906  TimetableChangedFlag = true;
3907  TimetableValidFlag = false;
3908  TTEntryChangedFlag = false;
3909  TEVPtr = 0;
3911  TTFirstServicePtr = 0;
3912  TTLastServicePtr = 0; // all set to null to begin with
3913  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3914  // position changing in AllEntriesTTListBox
3915  AllEntriesTTListBox->Clear();
3917  if(TimetableEditVector.empty())
3918  {
3920  SetLevel1Mode(109);
3921  Utilities->CallLogPop(1777);
3922  return;
3923  }
3924 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed at v2.5.0
3925 // but vector pointers unreliable after an erase, so use the position in the vector
3926  if(OldVectorPos == 0)
3927  {
3929  }
3930  else
3931  {
3932  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3933  }
3934  if(TTCurrentEntryPtr == 0)
3935  {
3936  OneEntryTimetableMemo->Clear();
3937  }
3939  SetLevel1Mode(115);
3940  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3941  {
3943  }
3944  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3945  {
3946  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3947  }
3948  else
3949  {
3950  AllEntriesTTListBox->TopIndex = TopPos;
3951  }
3952  Utilities->CallLogPop(1676);
3953  }
3954  catch(const Exception &e)
3955  {
3956  ErrorLog(111, e.Message);
3957  }
3958 }
3959 
3960 // ---------------------------------------------------------------------------
3961 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3962 {
3963  try
3964  {
3965  TrainController->LogEvent("PasteTTEntryButtonClick");
3966  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3967  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3968  {
3969  Utilities->CallLogPop(1637);
3970  return;
3971  }
3972  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3973  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3974  // after the current Entry - may be at the end
3975  TimetableChangedFlag = true;
3976  TimetableValidFlag = false;
3977  TTEntryChangedFlag = false;
3978  TEVPtr = 0;
3980  TTFirstServicePtr = 0;
3981  TTLastServicePtr = 0; // all set to null to begin with
3982  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3983  // position changing in AllEntriesTTListBox
3984  AllEntriesTTListBox->Clear();
3986  if(TimetableEditVector.empty())
3987  {
3989  SetLevel1Mode(110);
3990  Utilities->CallLogPop(1778);
3991  return;
3992  }
3993 // restore TTCurrentEntryPtr
3994  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3995  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3996 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3998  SetLevel1Mode(94);
3999  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4000  {
4002  }
4003  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4004  {
4005  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4006  }
4007  else
4008  {
4009  AllEntriesTTListBox->TopIndex = TopPos;
4010  }
4011  Utilities->CallLogPop(1620);
4012  }
4013  catch(const Exception &e)
4014  {
4015  ErrorLog(57, e.Message);
4016  }
4017 }
4018 // ---------------------------------------------------------------------------
4019 
4020 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
4021 {
4022  try
4023  {
4024  TrainController->LogEvent("DeleteTTEntryButtonClick");
4025  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
4026  if(TTCurrentEntryPtr == 0)
4027  {
4028  Utilities->CallLogPop(1645);
4029  return;
4030  }
4031  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
4032  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4033  if(button == IDNO)
4034  {
4035  Utilities->CallLogPop(1663);
4036  return;
4037  }
4038  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
4039  // so use the position in the vector
4041 
4042 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
4043 // pick up the start time if there is one
4044  TimetableChangedFlag = true;
4045  TimetableValidFlag = false;
4046  TTEntryChangedFlag = false;
4047  TEVPtr = 0;
4049  TTFirstServicePtr = 0;
4050  TTLastServicePtr = 0; // all set to null to begin with
4051  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4052  // position changing in AllEntriesTTListBox
4053  AllEntriesTTListBox->Clear();
4055  if(TimetableEditVector.empty())
4056  {
4058  SetLevel1Mode(111);
4059  Utilities->CallLogPop(1779);
4060  return;
4061  }
4062 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
4063 // but vector pointers unreliable after an erase, so use the position in the vector
4064  if(OldVectorPos == 0)
4065  {
4067  }
4068  else
4069  {
4070  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
4071  }
4072  if(TTCurrentEntryPtr == 0)
4073  {
4074  OneEntryTimetableMemo->Clear();
4075  }
4077  SetLevel1Mode(95);
4078  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4079  {
4081  }
4082  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4083  {
4084  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4085  }
4086  else
4087  {
4088  AllEntriesTTListBox->TopIndex = TopPos;
4089  }
4090  Utilities->CallLogPop(1621);
4091  }
4092  catch(const Exception &e)
4093  {
4094  ErrorLog(58, e.Message);
4095  }
4096 }
4097 // ---------------------------------------------------------------------------
4098 
4099 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
4100 {
4101  try
4102  {
4103  TrainController->LogEvent("SaveTTEntryButtonClick");
4104  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
4105 /* allow blank lines to be saved
4106  AnsiString ContentStr = OneEntryTimetableMemo->Text;
4107  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
4108  {
4109  Utilities->CallLogPop(1679);
4110  return;
4111  }
4112 */
4113  AnsiString TempStr = "";
4114  bool ActiveLine = false;
4115  if(TTCurrentEntryPtr > 0)
4116  {
4117  if(*TTCurrentEntryPtr != "")
4118  {
4120  {
4121  ActiveLine = true;
4122  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
4123  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
4124  {
4125  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
4126  {
4127  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
4128  }
4129  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
4130  {
4131  TempStr += ',';
4132  }
4133  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
4134  // ends the timetable
4135  }
4136  // strip any excess commas from the end
4137  if(TempStr != "")
4138  {
4139  while(TempStr[TempStr.Length()] == ',')
4140  {
4141  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
4142  if(TempStr == "")
4143  {
4144  break;
4145  }
4146  }
4147  }
4148  }
4149  }
4150  }
4151  if(!ActiveLine)
4152  {
4153  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
4154  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
4155  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
4156  // and before a blank line or end of file, so the syntax check will work OK
4157  }
4158  if(AZOrderButton->Caption == AnsiString("Original Order"))
4159  {
4161  }
4162  TimetableValidFlag = false;
4163  TimetableChangedFlag = true;
4164  TTEntryChangedFlag = false;
4165  int TopPos;
4166  if(TTCurrentEntryPtr == 0)
4167  {
4169  }
4171  {
4172  (*TTCurrentEntryPtr) = TempStr;
4173  // need to reset the AllEntriesTTListBox in case the headcode has changed
4174  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4175  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4176  // position changing in AllEntriesTTListBox
4177  AllEntriesTTListBox->Clear();
4179  if(TimetableEditVector.empty())
4180  {
4182  SetLevel1Mode(112);
4183  Utilities->CallLogPop(1780);
4184  return;
4185  }
4186  // restore TTCurrentEntryPtr
4187  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4188  }
4189  else
4190  {
4191  NewEntryInPreparationFlag = false;
4192  if(TTCurrentEntryPtr != 0)
4193  {
4194  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4195  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
4196  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4198  }
4199  else
4200  {
4201  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
4203  }
4204  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
4205  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4206  // position changing in AllEntriesTTListBox
4207  AllEntriesTTListBox->Clear();
4209  if(TimetableEditVector.empty())
4210  {
4212  SetLevel1Mode(113);
4213  Utilities->CallLogPop(1781);
4214  return;
4215  }
4216 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4217  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4218  {
4220  }
4221  else
4222  {
4223  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4224  }
4225  }
4227  SetLevel1Mode(96);
4228  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4229  {
4231  }
4232  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4233  {
4234  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4235  }
4236  else
4237  {
4238  AllEntriesTTListBox->TopIndex = TopPos;
4239  }
4240  Utilities->CallLogPop(1622);
4241  }
4242  catch(const Exception &e)
4243  {
4244  ErrorLog(59, e.Message);
4245  }
4246 }
4247 // ---------------------------------------------------------------------------
4248 
4249 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
4250 {
4251  try
4252  {
4253  TrainController->LogEvent("SaveTTButtonClick");
4254  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
4255  if(TimetableEditVector.empty())
4256  {
4257  ShowMessage("Timetable is empty, can't save an empty timetable");
4258  Utilities->CallLogPop(1685);
4259  return;
4260  }
4261  std::ofstream TTBLFile;
4262  if(CreateEditTTFileName != "")
4263  {
4264  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4265  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4266  }
4267  else
4268  {
4269  if(SaveTTDialog->Execute())
4270  {
4271  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4272  {
4273  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4274  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4275  }
4276  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
4277  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
4278  {
4279  if(CreateEditTTFileName[x] == '\\')
4280  {
4281  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4282  break;
4283  }
4284  }
4285  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4286  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4287  }
4288  else // cancelled dialog
4289  {
4291  SetLevel1Mode(137);
4292  Utilities->CallLogPop(2205);
4293  return;
4294  }
4295  }
4296  if(TTBLFile.is_open())
4297  {
4298  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4299  {
4300  TTBLFile << (*TEVPtr).c_str() << '\0';
4301  }
4302  TimetableChangedFlag = false;
4303  TTBLFile.close();
4304  }
4305  else
4306  {
4307  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4308  }
4310  SetLevel1Mode(97);
4311  Utilities->CallLogPop(1623);
4312  }
4313  catch(const Exception &e)
4314  {
4315  ErrorLog(60, e.Message);
4316  }
4317 }
4318 // ---------------------------------------------------------------------------
4319 
4320 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
4321 {
4322  try
4323  {
4324  TrainController->LogEvent("SaveTTAsButtonClick");
4325  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4326  if(TimetableEditVector.empty())
4327  {
4328  ShowMessage("Timetable is empty, can't save an empty timetable");
4329  Utilities->CallLogPop(1686);
4330  return;
4331  }
4332  std::ofstream TTBLFile;
4333  if(SaveTTDialog->Execute())
4334  {
4335  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName)) // new at v2.6.0 to retain a new directory
4336  {
4337  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4338  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4339  }
4340  CreateEditTTFileName = SaveTTDialog->FileName;
4341  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4342  {
4343  if(SaveTTDialog->FileName[x] == '\\')
4344  {
4345  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4346  break;
4347  }
4348  }
4349  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4350  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4351  }
4352  else // cancelled dialog
4353  {
4355  SetLevel1Mode(138);
4356  Utilities->CallLogPop(2206);
4357  return;
4358  }
4359  if(TTBLFile.is_open())
4360  {
4361  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4362  {
4363  TTBLFile << (*TEVPtr).c_str() << '\0';
4364  }
4365  TimetableChangedFlag = false;
4366  TTBLFile.close();
4367  }
4368  else
4369  {
4370  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4371  }
4373  SetLevel1Mode(117);
4374  Utilities->CallLogPop(1667);
4375  }
4376  catch(const Exception &e)
4377  {
4378  ErrorLog(108, e.Message);
4379  }
4380 }
4381 // ---------------------------------------------------------------------------
4382 
4383 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4384 {
4385  try
4386  {
4387  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4388  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4389  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4390  bool EndOfFile = false;
4391  bool FinalCallFalse = false;
4392  bool GiveMessagesTrue = true;
4393  bool CheckLocationsExistInRailway = false;
4394  if(RlyFile)
4395  {
4396  CheckLocationsExistInRailway = true;
4397  }
4398 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4399  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4400  // return true for success
4401  {
4402  ShowMessage(
4403  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4404  }
4406  SetLevel1Mode(98);
4407  Utilities->CallLogPop(1624);
4408  }
4409  catch(const Exception &e)
4410  {
4411  ErrorLog(61, e.Message);
4412  }
4413 }
4414 // ---------------------------------------------------------------------------
4415 
4416 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4417 {
4418  try
4419  {
4420  TrainController->LogEvent("ValidateTimetableButtonClick");
4421  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4422  // reset all message flags, stops them being given twice new at v2.4.0
4423  TrainController->SSHigh = false;
4424  TrainController->MRSHigh = false;
4425  TrainController->MRSLow = false;
4426  TrainController->MassHigh = false;
4427  TrainController->BFHigh = false;
4428  TrainController->BFLow = false;
4429  TrainController->PwrHigh = false;
4430  TrainController->SigSHigh = false;
4431  TrainController->SigSLow = false;
4432  if(CreateEditTTFileName == "")
4433  {
4434  Utilities->CallLogPop(1664);
4435  return;
4436  }
4437  bool CheckLocationsExistInRailwayTrue = true;
4438  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4439  {
4440  Screen->Cursor = TCursor(-11); // Hourglass;
4441  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4442  if(TTBLFile.is_open())
4443  {
4444  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4445  {
4446  if(!TwoLocationNamePanel->Visible) //added at v2.9.1. If this visible don't override it with another message.
4447  {
4448  ShowMessage("Timetable integrity OK");
4449  TimetableValidFlag = true;
4450  }
4451 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4452  }
4453  }
4454  else
4455  {
4456  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
4457  }
4458  Screen->Cursor = TCursor(-2); // Arrow
4459  } // if(TimetableIntegrityCheck
4460  else
4461  {
4462 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4463  }
4465  SetLevel1Mode(99);
4466  Utilities->CallLogPop(1625);
4467  }
4468  catch(const Exception &e)
4469  {
4470  ErrorLog(62, e.Message);
4471  }
4472 }
4473 
4474 // ---------------------------------------------------------------------------
4475 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4476 {
4477  try
4478  {
4479  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4480  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4481  if(TTCurrentEntryPtr == 0)
4482  {
4483  Utilities->CallLogPop(1634);
4484  return;
4485  }
4486  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4487  {
4488  Utilities->CallLogPop(1632);
4489  return;
4490  }
4491  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4492  AnsiString TempStr = *TEVPtr;
4494  *TTCurrentEntryPtr = TempStr;
4496  TimetableChangedFlag = true;
4497  TimetableValidFlag = false;
4498 
4499 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4500  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4501  // position changing in AllEntriesTTListBox
4502  AllEntriesTTListBox->Clear();
4503  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4505 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4506  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4507  {
4509  }
4510  else
4511  {
4512  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4513  }
4515  SetLevel1Mode(100);
4516  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4517  {
4519  }
4520  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4521  {
4522  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4523  }
4524  else
4525  {
4526  AllEntriesTTListBox->TopIndex = TopPos;
4527  }
4528  Utilities->CallLogPop(1626);
4529  }
4530  catch(const Exception &e)
4531  {
4532  ErrorLog(63, e.Message);
4533  }
4534 }
4535 // ---------------------------------------------------------------------------
4536 
4537 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4538 {
4539  try
4540  {
4541  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4542  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4543  if(TTCurrentEntryPtr == 0)
4544  {
4545  Utilities->CallLogPop(1635);
4546  return;
4547  }
4548  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4549  {
4550  Utilities->CallLogPop(1678);
4551  return;
4552  }
4553  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4554  AnsiString TempStr = *TEVPtr;
4556  *TTCurrentEntryPtr = TempStr;
4558  TimetableChangedFlag = true;
4559  TimetableValidFlag = false;
4560 
4561 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4562  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4563  // position changing in AllEntriesTTListBox
4564  AllEntriesTTListBox->Clear();
4565  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4567 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4568  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4569  {
4571  }
4572  else
4573  {
4574  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4575  }
4577  SetLevel1Mode(101);
4578  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4579  {
4581  }
4582  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4583  {
4584  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4585  }
4586  else
4587  {
4588  AllEntriesTTListBox->TopIndex = TopPos;
4589  }
4590  Utilities->CallLogPop(1627);
4591  }
4592  catch(const Exception &e)
4593  {
4594  ErrorLog(64, e.Message);
4595  }
4596 }
4597 
4598 // ---------------------------------------------------------------------------
4599 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4600 {
4601  try
4602  {
4603  TrainController->LogEvent("CancelTTActionButtonClick");
4604  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4605  TTEntryChangedFlag = false;
4607  {
4608  NewEntryInPreparationFlag = false;
4609  OneEntryTimetableMemo->Clear();
4610  }
4611  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4612  // position changing in AllEntriesTTListBox
4614  SetLevel1Mode(102);
4615  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4616  {
4618  }
4619  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4620  {
4621  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4622  }
4623  else
4624  {
4625  AllEntriesTTListBox->TopIndex = TopPos;
4626  }
4627  Utilities->CallLogPop(1630);
4628  }
4629  catch(const Exception &e)
4630  {
4631  ErrorLog(102, e.Message);
4632  }
4633 }
4634 
4635 // ---------------------------------------------------------------------------
4636 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4637 {
4638  try
4639  {
4640  TrainController->LogEvent("RestoreTTButtonClick");
4641  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4643  {
4644  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4645  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4646  if(button == IDNO)
4647  {
4648  Utilities->CallLogPop(1651);
4649  return;
4650  }
4651  }
4652  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4653  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4654  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4655  if(TTBLFile.is_open())
4656  {
4657  TimetableChangedFlag = false;
4658  TimetableValidFlag = false;
4659  TTEntryChangedFlag = false;
4660  NewEntryInPreparationFlag = false;
4661  CopiedEntryFlag = false;
4662  CopiedEntryStr = "";
4663  TimetableEditVector.clear();
4664  OneEntryTimetableMemo->Clear();
4665  AllEntriesTTListBox->Clear();
4666  TTStartTimeBox->Text = "";
4667  AddSubMinsBox->Text = "";
4668  TEVPtr = 0;
4670  TTFirstServicePtr = 0;
4671  TTLastServicePtr = 0; // all set to null to begin with
4672  char *TimetableEntryString = new char[10000];
4673  while(true)
4674  {
4675  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4676  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4677  {
4678  // may still have eof even if read a line, and
4679  // if so need to process it
4680  break;
4681  }
4682  AnsiString OneLine(TimetableEntryString);
4683  TimetableEditVector.push_back(OneLine);
4684  }
4685  TTBLFile.close();
4686  delete[]TimetableEntryString;
4687  // here with TimetableEditVector compiled
4688  }
4689  else
4690  {
4691  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
4692  Utilities->CallLogPop(1655);
4693  return;
4694  }
4696  if(TimetableEditVector.empty())
4697  {
4699  SetLevel1Mode(114);
4700  Utilities->CallLogPop(1782);
4701  return;
4702  }
4703 // all now set where can be
4705 // end of repeat from EditTimetableMenuItemClick
4706 
4708  SetLevel1Mode(104);
4709  Utilities->CallLogPop(1652);
4710  }
4711  catch(const Exception &e)
4712  {
4713  ErrorLog(104, e.Message);
4714  }
4715 }
4716 
4717 // ---------------------------------------------------------------------------
4718 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4719 {
4720  try
4721  {
4722  TrainController->LogEvent("ExportTTButtonClick");
4723  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4724  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4725  {
4726  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4727  Utilities->CallLogPop(1698);
4728  return;
4729  }
4730 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4731 // the message instead, but reset here afterwards
4732  AnsiString TTTitle;
4734  {
4735  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4736  {
4737  if(CreateEditTTFileName[x] == '\\')
4738  {
4739  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4740  break;
4741  }
4742  }
4744  }
4745  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4747  SetLevel1Mode(116);
4748  Utilities->CallLogPop(1662);
4749  }
4750  catch(const Exception &e)
4751  {
4752  ErrorLog(107, e.Message);
4753  }
4754 }
4755 
4756 // ---------------------------------------------------------------------------
4757 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4758 {
4759  try
4760  {
4761  TrainController->LogEvent("TTTextButtonClick");
4762  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4763 /*
4764  if(TTStartTimePtr == 0)
4765  {
4766  OneEntryTimetableMemo->Clear();
4767  TTStartTimeBox->SetFocus();
4768  Utilities->CallLogPop(1673);
4769  return;
4770  }
4771 */
4772  int SelPos = OneEntryTimetableMemo->SelStart;
4773  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4774  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4775  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4776  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4777  TTEntryChangedFlag = true;
4778  OneEntryTimetableMemo->SetFocus();
4780  SetLevel1Mode(119);
4781  Utilities->CallLogPop(1672);
4782  }
4783  catch(const Exception &e)
4784  {
4785  ErrorLog(110, e.Message);
4786  }
4787 }
4788 
4789 // ---------------------------------------------------------------------------
4790 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4791 {
4792  try
4793  {
4794  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4795  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4797  {
4798  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4799  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4800  if(button == IDNO)
4801  {
4802  Utilities->CallLogPop(1603);
4803  return;
4804  }
4805  }
4806  TimetableChangedFlag = false;
4807  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4808  // added for Beta v0.2b
4809  CreateEditTTTitle = ""; // as above
4810  ConflictPanel->Visible = false;
4811  Level1Mode = BaseMode;
4812  SetLevel1Mode(84);
4813  Utilities->CallLogPop(1606);
4814  }
4815  catch(const Exception &e)
4816  {
4817  ErrorLog(49, e.Message);
4818  }
4819 }
4820 
4821 // ---------------------------------------------------------------------------
4822 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4823 {
4824  try
4825  {
4826  TrainController->LogEvent("LocationNameComboBoxClick");
4827  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4828  if(TTStartTimePtr != 0)
4829  {
4830  LocationNameComboBox->SelectAll();
4831  int SelPos = OneEntryTimetableMemo->SelStart;
4832  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4833  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4834  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4835  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4836  TTEntryChangedFlag = true;
4837  OneEntryTimetableMemo->SetFocus();
4839  SetLevel1Mode(118);
4840  }
4841  Utilities->CallLogPop(1669);
4842  }
4843  catch(const Exception &e)
4844  {
4845  ErrorLog(109, e.Message);
4846  }
4847 }
4848 
4849 // ---------------------------------------------------------------------------
4850 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4851 {
4852  try
4853  {
4854 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4855  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4857  {
4858  Utilities->CallLogPop(1716);
4859  return;
4860  }
4861  TimetableChangedFlag = true;
4862  TTEntryChangedFlag = true;
4863  TimetableValidFlag = false;
4865  SetLevel1Mode(127);
4866  Utilities->CallLogPop(1629);
4867  }
4868  catch(const Exception &e)
4869  {
4870  ErrorLog(66, e.Message);
4871  }
4872 }
4873 
4874 // ---------------------------------------------------------------------------
4875 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4876 {
4877 // forces a recheck for whether addmins/submins buttons should be enabled
4878  try
4879  {
4880  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4881  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4883  SetLevel1Mode(108);
4884  Utilities->CallLogPop(1658);
4885  }
4886  catch(const Exception &e)
4887  {
4888  ErrorLog(106, e.Message);
4889  }
4890 }
4891 
4892 // ---------------------------------------------------------------------------
4893 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4894 {
4895  try
4896  {
4897  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4898  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4899  if(!Track->LocationNameMultiMap.empty())
4900  {
4901  LocationNameComboBox->Text = "Location names";
4902  }
4903  else
4904  {
4905  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4906  }
4907  Utilities->CallLogPop(1677);
4908  }
4909  catch(const Exception &e)
4910  {
4911  ErrorLog(112, e.Message);
4912  }
4913 }
4914 
4915 // ---------------------------------------------------------------------------
4916 
4917 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4918 {
4919 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4920  try
4921  {
4922  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4923  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4924  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4925  {
4926  Utilities->CallLogPop(1687);
4927  return;
4928  }
4929  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4930  {
4931  Utilities->CallLogPop(1688);
4932  return;
4933  }
4934  // find item required - 13 pixels per line of text
4935  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4936  // position changing in AllEntriesTTListBox
4937  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4938  {
4940  }
4941  else
4942  {
4943  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4944  }
4945  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4947 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4948  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4949  {
4951  }
4952  else
4953  {
4954  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4955  }
4957  SetLevel1Mode(120);
4958  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4959  Utilities->CallLogPop(1648);
4960  }
4961  catch(const Exception &e)
4962  {
4963  ErrorLog(103, e.Message);
4964  }
4965 }
4966 
4967 // ---------------------------------------------------------------------------
4968 
4969 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4970 {
4971 // Mouseup rather than Mousedown so shows floating label when over selected train
4972  try
4973  {
4974  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y) + "," + AnsiString(Button)); // button may be right or left
4975  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4976  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4977  {
4978  Utilities->CallLogPop(2087);
4979  return;
4980  }
4982  {
4983  Utilities->CallLogPop(2088);
4984  return;
4985  }
4986  int HPos, VPos, TrainID = -1, TrackVectorPosition = -1;
4987  if(!GetTrainIDOrContinuationPosition(0, X, Y, TrainID, TrackVectorPosition))
4988  {
4989  OAListBoxRightMouseButtonDown = false; // so resets when button over blank area
4990  Utilities->CallLogPop(2260);
4991  return;
4992  }
4993  if(Button == mbLeft) // added at v2.7.0 to keep right button for train information
4994  {
4995  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4996  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4997  // now want to set the offsets to display HPos & VPos in the centre of the screen
4998  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4999  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
5000  int ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
5001  int ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
5002  if(Display->ZoomOutFlag) // panel displays in either zoom mode
5003  {
5004  Display->ZoomOutFlag = false;
5006  }
5007  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
5008  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
5009  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
5010  Mouse->CursorPos = CursPos;
5011  }
5012  else // mbRight, reset OAListBoxRightMouseButtonDown
5013  {
5015  }
5016  Utilities->CallLogPop(2090);
5017  }
5018  catch(const Exception &e)
5019  {
5020  ErrorLog(200, e.Message);
5021  }
5022 }
5023 
5024 // ---------------------------------------------------------------------------
5025 
5026 void __fastcall TInterface::OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5027 {
5028  try
5029  {
5030  TrainController->LogEvent("OAListBoxMouseDown," + AnsiString(X) + "," + AnsiString(Y));
5031  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseDown");
5032  if(Button == mbRight)
5033  {
5035  }
5036  Utilities->CallLogPop(2264);
5037  }
5038  catch(const Exception &e)
5039  {
5040  ErrorLog(220, e.Message);
5041  }
5042 }
5043 
5044 // ---------------------------------------------------------------------------
5045 
5046 bool TInterface::GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &TrackVectorPosition)
5047 // returns true if value(s) valid
5048 {
5049  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetTrainIDOrContinuationPosition");
5051  // find item required - 13 pixels per line of text
5052  int TopPos = OAListBox->TopIndex;
5053  int OAIndex;
5054  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
5055  {
5056  Utilities->CallLogPop(2089);
5057  return(false);
5058  }
5059  else
5060  {
5061  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
5062  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
5063  }
5064  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
5065  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
5066  {
5067  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
5068  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
5069  // as notified by Rokas Serys by email on 16/05/20
5070  {
5071  TrainID = TrainIDorTVPos;
5072  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
5073  }
5074  else
5075  {
5076  Utilities->CallLogPop(2155); // if not there then ignore
5077  return(false);
5078  }
5079  }
5080  else // train to enter at a continuation, so value is -TVPos of continuation - 1
5081  {
5082  TrackVectorPosition = -(TrainIDorTVPos + 1);
5083  }
5084  Utilities->CallLogPop(2261);
5085  return(true);
5086 }
5087 
5088 // ---------------------------------------------------------------------------
5089 
5091 {
5092  enum
5093  {
5094  PreStartTime, ActiveSegment, PostEnd
5095  } Segment;
5096  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
5097  AllEntriesTTListBox->Clear();
5098  TEVPtr = 0;
5099  TTStartTimePtr = 0;
5100  TTFirstServicePtr = 0;
5101  TTLastServicePtr = 0; // all set to null to begin with
5102  if(TimetableEditVector.empty())
5103  {
5104  TTCurrentEntryPtr = 0;
5105  Utilities->CallLogPop(1681);
5106  return;
5107  }
5108  Segment = PreStartTime;
5109  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
5110  {
5111  if(Segment == PreStartTime) // looking for the start time
5112  {
5113  TDateTime TempTime; // dummy
5114  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
5115  {
5116  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
5117  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
5118  Segment = ActiveSegment;
5119  continue;
5120  }
5121  else
5122  {
5123  if(*TEVPtr == "")
5124  {
5125  AllEntriesTTListBox->Items->Add("- Blank");
5126  }
5127  else
5128  {
5129  AnsiString CurrentStr = *TEVPtr;
5130  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5131  {
5132  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
5133  for(int x = 1; x < CurrentStr.Length(); x++)
5134  {
5135  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5136  {
5137  CurrentStr = CurrentStr.SubString(1, (x - 1));
5138  }
5139  }
5140  }
5141  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
5142  }
5143  continue;
5144  }
5145  }
5146  if(Segment == ActiveSegment)
5147  {
5148  if(*TEVPtr != "")
5149  {
5150  if((*TEVPtr)[1] != '*')
5151  {
5153  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
5154  // SaveTTEntryButtonClick - see comment in that function
5155  if(TTFirstServicePtr == 0)
5156  {
5158  }
5160  }
5161  AnsiString Entry = *TEVPtr;
5162 
5163 /* dropped at v2.9.1 so comment entries more meaningful, they self truncate to AllEntriesTTListBox width
5164  if(Entry[1] == '*')
5165  {
5166  Entry = "Comment";
5167  }
5168 */
5169  if(Entry[1] != '*') //changed from 'else' at v2.9.1
5170  {
5171  int SCPos = Entry.Pos(';'); // semicolon
5172  int CPos = Entry.Pos(','); // comma
5173  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
5174  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
5175  // description - enter the text up to the comma
5176  // both, semicolon before comma, normal - enter text up to the semicolon
5177  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
5178  // semicolon & no comma - enter text up to the semicolon
5179  if((CPos == 0) && (SCPos == 0))
5180  {
5181  Entry = Entry.SubString(1, 12);
5182  }
5183  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
5184  {
5185  Entry = Entry.SubString(1, CPos - 1);
5186  }
5187  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
5188  {
5189  Entry = Entry.SubString(1, SCPos - 1);
5190  }
5191  else if((CPos > 0) && (SCPos == 0))
5192  {
5193  Entry = Entry.SubString(1, CPos - 1);
5194  }
5195  else
5196  {
5197  Entry = Entry.SubString(1, SCPos - 1);
5198  }
5199  }
5200  AllEntriesTTListBox->Items->Add(Entry);
5201  continue;
5202  }
5203  else
5204  {
5205  Segment = PostEnd;
5206  AllEntriesTTListBox->Items->Add("END (Blank)");
5207  continue;
5208  }
5209  }
5210  if(Segment == PostEnd)
5211  {
5212  if(*TEVPtr == "")
5213  {
5214  AllEntriesTTListBox->Items->Add("+ Blank");
5215  }
5216  else
5217  {
5218  AnsiString CurrentStr = *TEVPtr;
5219  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5220  {
5221  CurrentStr = CurrentStr.SubString(1, 10);
5222  for(int x = 1; x < CurrentStr.Length(); x++)
5223  {
5224  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5225  {
5226  CurrentStr = CurrentStr.SubString(1, (x - 1));
5227  }
5228  }
5229  }
5230  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
5231  }
5232  continue;
5233  }
5234  }
5235  if(TTStartTimePtr == 0)
5236  {
5237  TTStartTimeBox->Text = "";
5238  }
5239  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
5240  Utilities->CallLogPop(1680);
5241 }
5242 // ---------------------------------------------------------------------------
5243 
5244 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
5245 {
5246  try
5247  {
5248  if(TimetableEditVector.empty())
5249  {
5250  return; // should be able to access this if it is but keep in for safety
5251  }
5252  TrainController->LogEvent("AZOrderClick");
5253  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
5254  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
5255  {
5256  TTEVPtr SortStart, SortEnd;
5257  UnicodeString MessageStr =
5258  "If you wish to preserve the original order don't save any changes whilst in alphabetical order.\n\n" "To preserve the original order use alphabetical order to find the service required, click it to display it,"
5259  " then revert to the original order where the same service will be displayed and can be changed.";
5260  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
5263  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
5264  if(TTFirstServicePtr != NULL)
5265  {
5266  SortStart = TTFirstServicePtr;
5267  }
5268  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
5269  if(TTLastServicePtr != NULL)
5270  {
5271  SortEnd = TTLastServicePtr + 1;
5272  }
5273  std::sort(SortStart, SortEnd);
5275  bool CurrentEntryChanged = false;
5276  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5277  {
5278  if(TTSelectedEntry == *x)
5279  {
5280  TTCurrentEntryPtr = x;
5281  CurrentEntryChanged = true;
5282  }
5283  }
5284  if(!CurrentEntryChanged)
5285  {
5287  }
5288  AZOrderButton->Caption = AnsiString("Original Order");
5289  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
5290  }
5291  else
5292  {
5294  {
5295  UnicodeString MessageStr =
5296  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
5297  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
5298  if(button == IDNO)
5299  {
5300  TimetableChangedFlag = true;
5301  TimetableValidFlag = false;
5303  SetLevel1Mode(135);
5304  Utilities->CallLogPop(2166);
5305  return;
5306  }
5307  }
5311  bool CurrentEntryChanged = false;
5312  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5313  {
5314  if(TTSelectedEntry == *x)
5315  {
5316  TTCurrentEntryPtr = x;
5317  CurrentEntryChanged = true;
5318  }
5319  }
5320  if(!CurrentEntryChanged)
5321  {
5323  }
5324  AZOrderButton->Caption = AnsiString("A-Z Order");
5325  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
5326  }
5327  TimetableChangedFlag = true;
5328  TimetableValidFlag = false;
5331  SetLevel1Mode(136);
5332  Utilities->CallLogPop(2165);
5333  }
5334  catch(const Exception &e)
5335  {
5336  ErrorLog(211, e.Message);
5337  }
5338 }
5339 
5340 // ---------------------------------------------------------------------------
5341 
5342 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
5343 {
5344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
5345  AnsiString OutStr = "";
5346  int x = 1; // AnsiString arrays start at 1
5347 
5348  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
5349  {
5350  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
5351  {
5352  OutStr += ',';
5353  x++;
5354  x++;
5355  }
5356  else
5357  {
5358  OutStr += ConvStr[x];
5359  x++;
5360  }
5361  }
5362  if(x == ConvStr.Length())
5363  {
5364  OutStr += ConvStr[x]; // add the last character
5365 
5366  }
5367 // strip any excess commas from the end
5368  if(OutStr != "")
5369  {
5370  while(OutStr[OutStr.Length()] == ',')
5371  {
5372  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
5373  if(OutStr == "")
5374  {
5375  break; // if consisted of just commas then without this would fail on range error when becomes a null string
5376  }
5377  }
5378  }
5379  ConvStr = OutStr;
5380  if(ConvStr == "")
5381  {
5382  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
5383  }
5384  // when AllCommas will be true
5385  Utilities->CallLogPop(1846);
5386 }
5387 
5388 // ---------------------------------------------------------------------------
5389 
5391 {
5392 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5393  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5394  entries
5395 */
5396  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5397  PreviousTTEntryButton->Enabled = false;
5398  NextTTEntryButton->Enabled = false;
5399  AddMinsButton->Enabled = false;
5400  SubMinsButton->Enabled = false;
5401  CopyTTEntryButton->Enabled = false;
5402  CutTTEntryButton->Enabled = false;
5403  PasteTTEntryButton->Enabled = false;
5404  DeleteTTEntryButton->Enabled = false;
5405  SaveTTEntryButton->Enabled = false;
5406  SaveTTButton->Enabled = false;
5407  SaveTTAsButton->Enabled = false;
5408  ValidateTimetableButton->Enabled = false;
5409  AZOrderButton->Enabled = false;
5410  TTServiceSyntaxCheckButton->Enabled = false;
5411  NewTTEntryButton->Enabled = false;
5412  MoveTTEntryUpButton->Enabled = false;
5413  MoveTTEntryDownButton->Enabled = false;
5414  CancelTTEntryButton->Enabled = false;
5415  RestoreTTButton->Enabled = false;
5416  ExportTTButton->Enabled = false;
5417  ConflictAnalysisButton->Enabled = false;
5418  ExitTTModeButton->Enabled = true;
5419 
5421  {
5422  AZOrderButton->Enabled = true;
5423  }
5425  {
5426  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5427 
5428  }
5429  if(CreateEditTTFileName == "")
5430  {
5431  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5432  }
5433  else
5434  {
5435  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5436  }
5437  if(TTStartTimePtr != 0) // Null means start time not yet set
5438  {
5439  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5440  }
5441 // start time now set & displayed
5442 
5444  {
5445  InfoPanel->Visible = true;
5446  InfoPanel->Caption = "Select option or change entry";
5447  if(RailwayTitle != "")
5448  {
5449  ShowHideTTButton->Enabled = true;
5450  }
5451  else
5452  {
5453  ShowHideTTButton->Enabled = false;
5454  }
5455  ExitTTModeButton->Enabled = true;
5456  AllEntriesTTListBox->Enabled = true;
5457  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5458  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5459  {
5460  bool ValidFlag = true;
5461  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5462  {
5463  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5464  {
5465  ValidFlag = false;
5466  break;
5467  }
5468  }
5469  if(ValidFlag)
5470  {
5471  if(AnsiAddSubText.ToInt() != 0)
5472  {
5473  AddMinsButton->Enabled = true;
5474  SubMinsButton->Enabled = true;
5475  }
5476  }
5477  }
5479  {
5480  RestoreTTButton->Enabled = true;
5481  }
5483  {
5484  // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5485  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5486  ValidateTimetableButton->Enabled = true;
5487  }
5489  {
5490  ExportTTButton->Enabled = true;
5491  ConflictAnalysisButton->Enabled = true;
5492  }
5493  if(TTCurrentEntryPtr != 0)
5494  {
5495  CopyTTEntryButton->Enabled = true;
5496  CutTTEntryButton->Enabled = true;
5497  DeleteTTEntryButton->Enabled = true;
5498  }
5499  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5500  {
5501  SaveTTButton->Enabled = true;
5502  }
5503  if(!TimetableEditVector.empty())
5504  {
5505  SaveTTAsButton->Enabled = true;
5506  }
5508  {
5509  NewTTEntryButton->Enabled = true;
5510  }
5511  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5512  {
5513  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5514  {
5515  NextTTEntryButton->Enabled = true;
5516  MoveTTEntryDownButton->Enabled = true;
5517  }
5519  {
5520  PreviousTTEntryButton->Enabled = true;
5521  MoveTTEntryUpButton->Enabled = true;
5522  }
5523  }
5524  if(TTCurrentEntryPtr > 0)
5525  {
5526  if(*TTCurrentEntryPtr != "")
5527  {
5529  {
5530  TTServiceSyntaxCheckButton->Enabled = true;
5531  }
5532  }
5533  }
5534  if(CopiedEntryFlag)
5535  {
5536  PasteTTEntryButton->Enabled = true;
5537  }
5538  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5539  if(TTCurrentEntryPtr > 0)
5540  {
5541 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5543  {
5544  bool ServiceEntry = true;
5545  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5546  }
5547  else
5548  {
5549  bool ServiceEntry = false;
5550  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5551  }
5552  }
5553  }
5554  else
5555  {
5556  CancelTTEntryButton->Enabled = true;
5557  SaveTTEntryButton->Enabled = true;
5558  ShowHideTTButton->Enabled = false;
5559  ExitTTModeButton->Enabled = false;
5560  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5561  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5562  InfoPanel->Visible = true;
5563  }
5564  Utilities->CallLogPop(1600);
5565 }
5566 
5567 // ---------------------------------------------------------------------------
5568 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5569 {
5570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5571  AnsiString((short)ServiceEntry));
5572  OneEntryTimetableMemo->Clear();
5573  if(ServiceEntry)
5574  {
5575  TrainController->StripSpaces(1, Data);
5576  while(true)
5577  {
5578  int CommaPos = Data.Pos(',');
5579  if((CommaPos == 0) && (Data != ""))
5580  {
5581  CommaPos = Data.Length() + 1;
5582  }
5583  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5584  if(Data.Length() <= CommaPos)
5585  {
5586  break;
5587  }
5588  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5589  }
5590  }
5591  else
5592  {
5593  OneEntryTimetableMemo->Text = Data;
5594  }
5595  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5596 
5597  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5598  {
5599  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5600  TotalLines--;
5601  if(TotalLines < 1)
5602  {
5603  break;
5604  }
5605  }
5606  OneEntryTimetableMemo->HideSelection = true;
5607  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5608  OneEntryTimetableMemo->SelLength = 0;
5610  Utilities->CallLogPop(1602);
5611 }
5612 // ---------------------------------------------------------------------------
5613 
5615 {
5616  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5617  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5618  {
5619  HighlightPanel->Top = 32;
5620  HighlightPanel->Caption = "";
5621  HighlightPanel->Width = 100;
5622  HighlightPanel->Visible = false;
5623  }
5624  else
5625  {
5626  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5627  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5628  {
5629  for(int x = 1; x < CurrentStr.Length(); x++)
5630  {
5631  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5632  {
5633  CurrentStr = CurrentStr.SubString(1, (x - 1));
5634  }
5635  }
5636  }
5637  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5638  if(HighlightPanel->Top < 32)
5639  {
5640  HighlightPanel->Visible = false;
5641  }
5642  else
5643  {
5644  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5645  }
5646  HighlightPanel->Caption = CurrentStr;
5647  if(AllEntriesTTListBox->Items->Count > 47) // because the scrollbar will be present
5648  {
5649  HighlightPanel->Width = 82;
5650  }
5651  else
5652  {
5653  HighlightPanel->Width = 100;
5654  }
5655  }
5656  Utilities->CallLogPop(1709);
5657 }
5658 
5659 // ---------------------------------------------------------------------------
5661 {
5662  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5663  {
5664  return(false);
5665  }
5666  TDateTime DummyTime;
5667  bool TimesPresent = false;
5668 
5669  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5670  {
5671  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5672  {
5673  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5674  {
5675  TimesPresent = true;
5676  break;
5677  }
5678  }
5679  if(TimesPresent)
5680  {
5681  break;
5682  }
5683  }
5684  return(TimesPresent);
5685 }
5686 
5687 // ---------------------------------------------------------------------------
5688 // end of Timetable editing functions
5689 // ---------------------------------------------------------------------------
5690 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5691 {
5692  try
5693  {
5694  TrainController->LogEvent("ExitMenuItemClick");
5695  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5696 /* Dropped at v2.9.1 as serves no apparent purpose
5697  if(!FileChangedFlag && !(Track->IsTrackFinished()) && (EveryPrefDir->PrefDirSize() > 0))
5698  {
5699  UnicodeString MessageStr =
5700  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5701  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5702  if(button == IDNO)
5703  {
5704  Utilities->CallLogPop(1711);
5705  return;
5706  }
5707  }
5708 */
5709  if(FileChangedFlag)
5710  {
5711  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5712  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5713  if(button == IDNO)
5714  {
5715  Utilities->CallLogPop(1180);
5716  return;
5717  }
5718  }
5719  if((TempTTFileName != "") && FileExists(TempTTFileName))
5720  {
5721  DeleteFile(TempTTFileName);
5722  }
5723  Utilities->CallLogPop(1181);
5724  Application->Terminate();
5725  }
5726  catch(const Exception &e)
5727  {
5728  ErrorLog(140, e.Message);
5729  }
5730 }
5731 // ---------------------------------------------------------------------------
5732 
5733 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5734 {
5735  try
5736  {
5737  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5738  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5739  if(TrackInfoOnOffMenuItem->Caption == "Show")
5740  {
5741  TrackInfoOnOffMenuItem->Caption = "Hide";
5742  }
5743  else
5744  {
5745  TrackInfoOnOffMenuItem->Caption = "Show";
5746  }
5747  Utilities->CallLogPop(1183);
5748  }
5749  catch(const Exception &e)
5750  {
5751  ErrorLog(173, e.Message);
5752  }
5753 }
5754 // ---------------------------------------------------------------------------
5755 
5756 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5757 {
5758  try
5759  {
5760  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5761  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5762  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5763  {
5764  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5765  }
5766  else
5767  {
5768  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5769  }
5770  Utilities->CallLogPop(1184);
5771  }
5772  catch(const Exception &e)
5773  {
5774  ErrorLog(141, e.Message);
5775  }
5776 }
5777 
5778 // ---------------------------------------------------------------------------
5779 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5780 {
5781  try
5782  {
5783  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5784  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5785  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5786  {
5787  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5788  }
5789  else
5790  {
5791  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5792  }
5793  Utilities->CallLogPop(1185);
5794  }
5795  catch(const Exception &e)
5796  {
5797  ErrorLog(142, e.Message);
5798  }
5799 }
5800 
5801 // ---------------------------------------------------------------------------
5802 // Dragging Functions
5803 // ---------------------------------------------------------------------------
5804 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5805 {
5806 // allow in zoom out mode
5807  try
5808  {
5809 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5810  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5811  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5812  {
5813  Accept = true;
5814  int PPLeft = PerformancePanel->Left;
5815  int PPTop = PerformancePanel->Left;
5816 
5817  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5818  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5819  if((PPLeft + PerformancePanel->Width) < 32)
5820  {
5821  PPLeft = 32 - PerformancePanel->Width;
5822  }
5823  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5824  {
5825  PPLeft = MainScreen->Left + MainScreen->Width;
5826  }
5827  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5828  {
5829  PPTop = MainScreen->Top - PerformancePanel->Height;
5830  }
5831  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5832  {
5833  PPTop = MainScreen->Top + MainScreen->Height - 20;
5834  }
5835  PerformancePanel->Left = PPLeft;
5836  PerformancePanel->Top = PPTop;
5837  }
5838  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5839  // not the listbox because that used for selecting trains
5840  {
5841  Accept = true;
5842  int OALeft = OperatorActionPanel->Left;
5843  int OATop = OperatorActionPanel->Left;
5844 
5845  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5846  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5847  if((OALeft + OperatorActionPanel->Width) < 32)
5848  {
5849  OALeft = 32 - OperatorActionPanel->Width;
5850  }
5851  if(OALeft > (MainScreen->Left + MainScreen->Width))
5852  {
5853  OALeft = MainScreen->Left + MainScreen->Width;
5854  }
5855  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5856  {
5857  OATop = MainScreen->Top - OperatorActionPanel->Height;
5858  }
5859  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5860  {
5861  OATop = MainScreen->Top + MainScreen->Height - 20;
5862  }
5863  OperatorActionPanel->Left = OALeft;
5864  OperatorActionPanel->Top = OATop;
5865  }
5866  else
5867  {
5868  Accept = false;
5869  }
5870  Utilities->CallLogPop(1186);
5871  }
5872  catch(const Exception &e)
5873  {
5874  ErrorLog(143, e.Message);
5875  }
5876 }
5877 
5878 // ---------------------------------------------------------------------------
5879 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5880 {
5881 // allow in zoom out mode
5882  try
5883  {
5884  TrainController->LogEvent("PerformancePanelStartDrag");
5885  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5886  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5887  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5888  Utilities->CallLogPop(1187);
5889  }
5890  catch(const Exception &e)
5891  {
5892  ErrorLog(144, e.Message);
5893  }
5894 }
5895 // ---------------------------------------------------------------------------
5896 
5897 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5898 
5899 {
5900 // allow in zoom out mode
5901  try
5902  {
5903  TrainController->LogEvent("OperatorActionPanelStartDrag");
5904  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5905  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5906  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5907  Utilities->CallLogPop(2091);
5908  }
5909  catch(const Exception &e)
5910  {
5911  ErrorLog(201, e.Message);
5912  }
5913 }
5914 
5915 // ---------------------------------------------------------------------------
5916 // Mouse Functions
5917 // ---------------------------------------------------------------------------
5918 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5919 // caller function - stops master clock
5920 {
5921 // have to allow in zoom out mode
5922  try
5923  {
5924  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5925  bool ClockState = Utilities->Clock2Stopped;
5926  Utilities->Clock2Stopped = true;
5927 
5928  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5929  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5930  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5931  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5932  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5933  MMoveTrackSelFlag = false;
5934  MMovePrefDirSelFlag = false;
5938 
5940  {
5941  if(!Display->ZoomOutFlag)
5942  {
5943  MainScreenMouseDown2(0, Button, Shift, X, Y);
5944  }
5945  else
5946  {
5947  MainScreenMouseDown3(0, Button, Shift, X, Y);
5948  }
5949  }
5950  Utilities->Clock2Stopped = ClockState;
5951  Utilities->CallLogPop(33);
5952  }
5953  catch(const Exception &e)
5954  {
5955  ErrorLog(19, e.Message);
5956  }
5957 }
5958 
5959 // ---------------------------------------------------------------------------
5960 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5961 {
5962  try
5963  {
5964  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5965  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5966  "," + AnsiString(Y));
5967  // unplot GapFlash graphics if plotted & cancel gap flashing if left mouse button pressed (so can move display with right mouse button)
5968  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5969  if(Track->GapFlashFlag && !Display->ZoomOutFlag && (Button == mbLeft))
5970  {
5973  Track->GapFlashFlag = false;
5974  }
5975  int HLoc, VLoc;
5976  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5977  int NoOffsetX, NoOffsetY;
5978  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5979  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5980  {
5981  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5982  int Dummy; // unused in next function
5983  AnsiString Text = ""; // needed for TextFound but not used
5984  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X,
5985  Y, Dummy) && !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
5986  {
5989  WholeRailwayMoving = true;
5990  Screen->Cursor = TCursor(-22); // Four arrows;
5991  }
5992 
5993  else if(Level2TrackMode == AddText)
5994  {
5995  TrainController->LogEvent("mbRight + AddText");
5996 // ResetChangedFileDataAndCaption(, true); moved from here after 2.7.0 in case no changes made
5997  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
5998  {
5999  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
6000  {
6001  ResetChangedFileDataAndCaption(2, true); // moved to here after 2.7.0
6003  if(NoRailway())
6004  {
6005  EditMenu->Enabled = false;
6006  }
6007  else
6008  {
6009  EditMenu->Enabled = true;
6010  }
6011  }
6012  }
6013  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
6014  Utilities->CallLogPop(34);
6015  return;
6016  }
6017  else if(Level2TrackMode == AddGraphic)
6018  {
6019  TrainController->LogEvent("mbRight + AddGraphic");
6020  if(Track->UserGraphicVector.empty()) // no user graphics
6021  {
6022  Utilities->CallLogPop(2180);
6023  return;
6024  }
6025  int UGIVecPos;
6026  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
6027  {
6028  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
6030  if(NoRailway())
6031  {
6032  EditMenu->Enabled = false;
6033  }
6034  else
6035  {
6036  EditMenu->Enabled = true;
6037  }
6038  }
6039  Utilities->CallLogPop(2181);
6040  return;
6041  }
6042 
6043  else if(Level2TrackMode == AddTrack)
6044  {
6045  TrainController->LogEvent("mbRight + AddTrack");
6046  bool TrackEraseSuccessfulFlag;
6047  int ErasedTrackVectorPosition;
6048  Screen->Cursor = TCursor(-11); // Hourglass;
6049  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
6050  if(TrackEraseSuccessfulFlag)
6051  {
6052  if(ErasedTrackVectorPosition > -1) //may have been an inactive element
6053  {
6054  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
6055  }
6058  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
6059  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6060  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6061  if(Track->GapsUnset(1))
6062  {
6063  SetGapsButton->Enabled = true;
6064  }
6065  // only enable if there are gaps still to be set (returns false for no track)
6066  else
6067  {
6068  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
6069  {
6070  TrackOKButton->Enabled = true;
6071  }
6072  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6073  }
6074  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6075  {
6076  SetLengthsButton->Enabled = false;
6077  }
6078 // if(NoRailway()) dropped at v2.6.0 to allow edits during AddTrack
6079 // {
6080 // EditMenu->Enabled = false;
6081 // }
6082 // else
6083  EditMenu->Enabled = true;
6084  }
6085  Screen->Cursor = TCursor(-2); // Arrow
6086  Utilities->CallLogPop(35);
6087  return;
6088  }
6089  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
6090  {
6091  TrainController->LogEvent("mbRight + DistanceContinuing");
6092 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 as may only be checking existing distances/speeds. Moved to button clicks in TrackLengthPanel
6093  bool LeadingPointsAtLastElement = false;
6094  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
6095  {
6096  if(ConstructPrefDir->PrefDirSize() == 0)
6097  {
6099  SetLevel1Mode(64);
6101  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
6102  Utilities->CallLogPop(1526);
6103  return;
6104  }
6107  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6108  if(!LeadingPointsAtLastElement)
6109  {
6110  TrackLengthPanel->Visible = true;
6111  TrackLengthPanel->SetFocus();
6112  InfoPanel->Visible = true;
6113  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6114  RestoreAllDefaultLengthsButton->Enabled = true;
6115  ResetDefaultLengthButton->Enabled = true;
6116  LengthOKButton->Enabled = true;
6117  DistanceBox->Text = AnsiString(OverallDistance);
6118  if(OverallSpeedLimit > -1)
6119  {
6120  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6121  }
6122  else
6123  {
6124  SpeedLimitBox->Text = "Mixed";
6125  }
6126  }
6127  else
6128  {
6129  TrackLengthPanel->Visible = true;
6130  TrackLengthPanel->SetFocus();
6131  InfoPanel->Visible = true;
6132  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
6133  RestoreAllDefaultLengthsButton->Enabled = false;
6134  ResetDefaultLengthButton->Enabled = false;
6135  LengthOKButton->Enabled = false;
6136  }
6138  }
6139  Utilities->CallLogPop(36);
6140  return;
6141  }
6142 
6143  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
6144  {
6145  TrainController->LogEvent("mbRight + PrefDirContinuing");
6146 // ResetChangedFileDataAndCaption(, false); moved to later after 2.7.0 as may not change anything
6147 // RlyFile = false; - don't alter this just for PrefDir changes
6148  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
6149  {
6150  if(ConstructPrefDir->PrefDirSize() == 0)
6151  {
6153  SetLevel1Mode(14); // all PrefDir truncated
6154  Utilities->CallLogPop(37);
6155  return;
6156  }
6158  ResetChangedFileDataAndCaption(5, false); // moved to here after 2.7.0
6159  }
6161  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
6162  Utilities->CallLogPop(38);
6163  return;
6164  }
6165 
6166  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
6167  {
6168  TrainController->LogEvent("mbRight + != PrefDirContinuing");
6170 // RlyFile = false; - don't alter this just for PrefDir changes
6173  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
6174  Utilities->CallLogPop(39);
6175  return;
6176  }
6177 
6178  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
6179  {
6180  TrainController->LogEvent("mbRight + OperMode");
6181  bool FoundFlag;
6182  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
6183  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
6184  {
6186  // signaller control of train
6187  if(SelectedTrainID > -1)
6188  {
6191  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
6192  {
6193  if(Train.TrainMode == Signaller)
6194  {
6196  }
6197  }
6198  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
6200  !Train.StepForwardFlag))
6201  // don't allow signaller popup menu in timetable mode unless stopped,
6202  // or when coming to a stop or leaving at a continuation when under signaller control
6203  // or when failed
6204  {
6205  // don't allow selection if another stopped train at a bridge position
6206  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
6207  {
6208  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
6209  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
6210  if((TrainID01 > -1) && (TrainID23 > -1))
6211  {
6212  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
6213  Utilities->CallLogPop(1103);
6214  return;
6215  }
6216  }
6217  if(Train.TrainMode == Timetable)
6218  {
6219  TakeSignallerControlMenuItem->Enabled = true;
6220  TimetableControlMenuItem->Enabled = false;
6221  ChangeDirectionMenuItem->Enabled = false;
6222  MoveForwardsMenuItem->Enabled = false;
6223  SignallerJoinedByMenuItem->Enabled = false;
6224  RepairFailedTrainMenuItem->Enabled = false;
6225  StepForwardMenuItem->Enabled = false;
6226  RemoveTrainMenuItem->Enabled = false;
6227  PassRedSignalMenuItem->Enabled = false;
6228  SignallerControlStopMenuItem->Enabled = false;
6229  }
6230  else // signaller mode
6231  {
6232  TakeSignallerControlMenuItem->Enabled = false;
6233  if((Train.Crashed) || (Train.Derailed))
6234  {
6235  TimetableControlMenuItem->Enabled = false;
6236  ChangeDirectionMenuItem->Enabled = false;
6237  MoveForwardsMenuItem->Enabled = false;
6238  SignallerJoinedByMenuItem->Enabled = false;
6239  RepairFailedTrainMenuItem->Enabled = false;
6240  StepForwardMenuItem->Enabled = false;
6241  PassRedSignalMenuItem->Enabled = false;
6242  SignallerControlStopMenuItem->Enabled = false;
6243  RemoveTrainMenuItem->Enabled = true;
6244  }
6245  else if(Train.Stopped())
6246  {
6247  if(Train.TimetableFinished)
6248  {
6249  TimetableControlMenuItem->Enabled = false;
6250  }
6251  else
6252  {
6253  if(Train.RestoreTimetableLocation == "") // en route
6254  {
6255  TimetableControlMenuItem->Enabled = true;
6256  }
6257  else
6258  {
6259  // obtain train location & check if OK for restoration of tt control
6260  AnsiString LocName = "";
6261  if(Train.LeadElement > -1)
6262  {
6263  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
6264  }
6265  if((LocName == "") && (Train.MidElement > -1))
6266  {
6267  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
6268  }
6269  if(Train.RestoreTimetableLocation == LocName)
6270  {
6271  TimetableControlMenuItem->Enabled = true;
6272  }
6273  else
6274  {
6275  TimetableControlMenuItem->Enabled = false;
6276  }
6277  }
6278  }
6279 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
6280  ChangeDirectionMenuItem->Enabled = true;
6281  if(Train.LeadElement > -1)
6282  {
6284  {
6285  ChangeDirectionMenuItem->Enabled = false;
6286  }
6287  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
6288  {
6289  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
6290  .TrackType == Continuation)
6291  {
6292  ChangeDirectionMenuItem->Enabled = false;
6293  }
6294  }
6295  }
6296  else
6297  {
6298  ChangeDirectionMenuItem->Enabled = false;
6299  }
6300  if(Train.MidElement > -1)
6301  {
6303  {
6304  ChangeDirectionMenuItem->Enabled = false;
6305  }
6306  }
6307  else
6308  {
6309  ChangeDirectionMenuItem->Enabled = false;
6310  }
6311  if(Train.LagElement > -1)
6312  {
6314  {
6315  ChangeDirectionMenuItem->Enabled = false;
6316  }
6317  }
6318  RemoveTrainMenuItem->Enabled = true;
6319  SignallerControlStopMenuItem->Enabled = false;
6320  SignallerJoinedByMenuItem->Enabled = false;
6321  RepairFailedTrainMenuItem->Enabled = false;
6322  StepForwardMenuItem->Enabled = false;
6323  MoveForwardsMenuItem->Enabled = false;
6324  PassRedSignalMenuItem->Enabled = false;
6325  if(Train.AbleToMove(0))
6326  {
6327  MoveForwardsMenuItem->Enabled = true;
6329  {
6330  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
6331  }
6332  } // fails on trying to calc AutoSig time delay for resetting signals
6333 
6334  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
6335  {
6336  PassRedSignalMenuItem->Enabled = true;
6337  StepForwardMenuItem->Enabled = true;
6338  }
6339  TTrain *AdjacentTrain;
6340  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
6341  {
6342  SignallerJoinedByMenuItem->Enabled = true;
6343  }
6344  if(Train.TrainFailed)
6345  {
6346  RepairFailedTrainMenuItem->Enabled = true;
6347  }
6348  }
6349  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
6350  // mid move, & SetTrainMovementValues only intended to be called when stopped
6351  {
6352  TimetableControlMenuItem->Enabled = false;
6353  ChangeDirectionMenuItem->Enabled = false;
6354  RemoveTrainMenuItem->Enabled = false;
6355  MoveForwardsMenuItem->Enabled = false;
6356  SignallerJoinedByMenuItem->Enabled = false;
6357  RepairFailedTrainMenuItem->Enabled = false;
6358  PassRedSignalMenuItem->Enabled = false;
6359  StepForwardMenuItem->Enabled = false;
6360  SignallerControlStopMenuItem->Enabled = true;
6361  }
6362  }
6363  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
6364  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6366  PopupMenu->Popup(MainScreen->Left + X, MainScreen->Top + Y + 43); // menu stops everything so reset timetable time when restarts,
6367  // new at v2.6.1, displays so that can't inadvertently click on a selection if click twice
6368  // 43 is the distance from the top of the screen to the top of TInterface
6369  TrainController->BaseTime = TDateTime::CurrentDateTime();
6371  Utilities->CallLogPop(40);
6372  return;
6373  }
6374  }
6375  }
6376  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
6377  {
6378  TrainController->LogEvent("mbRight + RouteContinuing");
6380  Utilities->CallLogPop(41);
6381  return;
6382  }
6383 
6384  else if(RouteCancelFlag) // allow in PreStart
6385  {
6386  TrainController->LogEvent("mbRight + RouteCancelFlag");
6387  Screen->Cursor = TCursor(-11); // Hourglass;
6388  // stop clock as sometimes takes several seconds
6389  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6391  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
6392  {
6393  ClearandRebuildRailway(6); // to replot new shorter route
6394  }
6396  TrainController->BaseTime = TDateTime::CurrentDateTime();
6398  Screen->Cursor = TCursor(-2); // Arrow
6399  }
6400 
6401  else // gap flashing, don't allow to interfere with RouteCancelFlag
6402  {
6403  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
6404  int Position;
6405  TTrackElement TrackElement;
6406  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement))
6407  {
6408  ;
6409  }
6410  {
6411  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6412  {
6413  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
6414  {
6415  // don't flash if train on either gap element
6416  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6421  Track->GapFlashRedPosition = Position;
6426  Track->GapFlashFlag = true;
6427  }
6428  }
6429  }
6430  Utilities->CallLogPop(42);
6431  return; // covers above else & included here in case any more usermodes added later
6432  }
6433  }
6434  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
6435  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
6436  int Position;
6437  TTrackElement TrackElement;
6438  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement))
6439  {
6440  ;
6441  }
6442  {
6443  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6444  {
6445  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
6446  {
6447  // don't flash if train on either gap element
6448  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6452  Track->GapFlashRedPosition = Position;
6456  Track->GapFlashFlag = true;
6457  }
6458  }
6459  }
6460  Utilities->CallLogPop(67);
6461  return; // covers above else & included here in case any more usermodes added later
6462  }
6463 
6464 // Left Mouse Button Functions
6465  if(RouteCancelFlag)
6466  {
6468  }
6469  mbLeftDown = true;
6470 
6471  if(Level2TrackMode == AddTrack)
6472  {
6473  TrainController->LogEvent("mbLeft + AddTrack");
6474  Screen->Cursor = TCursor(-11); // Hourglass;
6476  bool TrackLinkingRequiredFlag;
6477  int CurrentTag;
6478  TSpeedButton *TempSpeedButton = 0;
6479  if(CurrentSpeedButton)
6480  {
6481  CurrentTag = CurrentSpeedButton->Tag;
6482  TempSpeedButton = CurrentSpeedButton;
6483  }
6484  else
6485  {
6486  CurrentTag = 0;
6487  }
6488  bool InternalChecks = true;
6489  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6490  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6491  EditMenu->Enabled = true;
6492  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6493  {
6494  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6495  }
6496  if(TrackLinkingRequiredFlag)
6497  {
6498  Track->SetTrackFinished(false);
6499  }
6500  SetTrackBuildImages(10);
6501  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6502  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6503  if(Track->GapsUnset(2))
6504  {
6505  SetGapsButton->Enabled = true;
6506  }
6507  // only enable if there are gaps still to be set (returns false for no track)
6508  else
6509  {
6510  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6511  {
6512  TrackOKButton->Enabled = true;
6513  }
6514  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6515  }
6516  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6517  {
6518  SetLengthsButton->Enabled = false;
6519  }
6520  if(TempSpeedButton) // restore button if was pressed
6521  {
6522  CurrentSpeedButton = TempSpeedButton;
6523  CurrentSpeedButton->Down = true;
6524  }
6525  Screen->Cursor = TCursor(-2); // Arrow
6526  Utilities->CallLogPop(44);
6527  return;
6528  }
6529 
6530  else if(Level2TrackMode == AddGraphic)
6531  {
6532  TrainController->LogEvent("mbLeft + AddGraphic");
6533 // ResetChangedFileDataAndCaption(, false); //moved to later after 2.7.0 in case can't find it
6534  TUserGraphicItem NewGI;
6535  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6536  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6537  {
6538  NewGI.UserGraphic = UGMIt->second;
6539  NewGI.Width = UGMIt->second->Width;
6540  NewGI.Height = UGMIt->second->Height;
6542  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6543  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6544  Track->UserGraphicVector.push_back(NewGI);
6545  Display->PlotAndAddUserGraphic(1, NewGI);
6546  ResetChangedFileDataAndCaption(24, false); // moved to here after 2.7.0
6547  }
6548  else
6549  {
6550  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6551  Utilities->CallLogPop(2195);
6552  return;
6553  }
6554  MoveTextOrGraphicButton->Enabled = true;
6555  EditMenu->Enabled = true;
6556  Utilities->CallLogPop(2182);
6557  return;
6558  }
6559 
6560  else if(Level2TrackMode == AddLocationName)
6561  {
6562  TrainController->LogEvent("mbLeft + AddLocationName");
6563 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to LocationNameKeyUp in case nothing changed
6564  bool FoundFlag;
6565  TTrackElement TrackElement;
6566  AnsiString NameString;
6567  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6568  if(!FoundFlag)
6569  {
6570  Utilities->CallLogPop(45);
6571  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6572  }
6573  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6574  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6575  TTrackElement& ValidElement = InactiveTrackElement1;
6576  unsigned int ValidPosition;
6577  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6578  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6579  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6580  {
6581  Utilities->CallLogPop(46);
6582  return; // element not valid
6583  }
6584  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6585  (InactiveTrackElement1.TrackType == Concourse))
6586  {
6587  ValidElement = InactiveTrackElement1;
6588  ValidPosition = InactivePair.first;
6589  }
6590  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6591  (InactiveTrackElement2.TrackType == Concourse))
6592  {
6593  ValidElement = InactiveTrackElement2;
6594  ValidPosition = InactivePair.second;
6595  }
6596  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6597 
6598  // put a square box round element to show selection
6599  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6600  LocationNameTextBox->Visible = true;
6601  LocationNameTextBox->SetFocus();
6602  NameString = Track->GetLocationName(ValidPosition);
6603  LocationNameTextBox->Text = NameString;
6604  InfoPanel->Visible = true;
6605  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6606 
6607  Track->LNPendingList.clear();
6608  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6609  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6610  Utilities->CallLogPop(47);
6611  return;
6612  }
6613 
6614  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6615  // prior to selecting start element
6616  {
6617  TrainController->LogEvent("mbLeft + DistanceStart");
6618 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6619  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6620  {
6623  SetLevel1Mode(65);
6625  SetLevel2TrackMode(30);
6626  }
6627  Utilities->CallLogPop(48);
6628  return;
6629  }
6630 
6631  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6632  // prior to selecting finish element
6633  {
6634  TrainController->LogEvent("mbLeft + DistanceContinuing");
6635 // ResetChangedFileDataAndCaption(, true); dropped after 2.7.0 in case only checking, moved to buttons in TracklengthPanel
6636  bool FinishElement = false, LeadingPointsAtLastElement = false;
6637  Screen->Cursor = TCursor(-11); // Hourglass;
6638  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6639  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6640  {
6641  // not same as start element
6642  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6643  {
6646  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6647  if(FinishElement)
6648  {
6649  TrackLengthPanel->Visible = true;
6650  TrackLengthPanel->SetFocus();
6651  InfoPanel->Visible = true;
6652  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6653  RestoreAllDefaultLengthsButton->Enabled = true;
6654  ResetDefaultLengthButton->Enabled = true;
6655  LengthOKButton->Enabled = true;
6656  DistanceBox->Text = AnsiString(OverallDistance);
6657  if(OverallSpeedLimit > -1)
6658  {
6659  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6660  }
6661  else
6662  {
6663  SpeedLimitBox->Text = "Mixed";
6664  }
6666  Screen->Cursor = TCursor(-2); // Arrow
6667  Utilities->CallLogPop(1527);
6668  return;
6669  }
6670  else
6671  {
6672  if(!LeadingPointsAtLastElement)
6673  {
6674  TrackLengthPanel->Visible = true;
6675  TrackLengthPanel->SetFocus();
6676  InfoPanel->Visible = true;
6677  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6678  RestoreAllDefaultLengthsButton->Enabled = true;
6679  ResetDefaultLengthButton->Enabled = true;
6680  LengthOKButton->Enabled = true;
6681  DistanceBox->Text = AnsiString(OverallDistance);
6682  if(OverallSpeedLimit > -1)
6683  {
6684  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6685  }
6686  else
6687  {
6688  SpeedLimitBox->Text = "Mixed";
6689  }
6690  // Level2TrackMode = DistanceContinuing;
6691  // SetLevel2TrackMode();
6692  }
6693  else
6694  {
6695  TrackLengthPanel->Visible = true;
6696  TrackLengthPanel->SetFocus();
6697  InfoPanel->Visible = true;
6698  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6699  RestoreAllDefaultLengthsButton->Enabled = false;
6700  ResetDefaultLengthButton->Enabled = false;
6701  LengthOKButton->Enabled = false;
6702  // Level2TrackMode = DistanceContinuing;
6703  // SetLevel2TrackMode();
6704  }
6705  }
6706  }
6707  }
6708  else // same as start element
6709  {
6712  SetLevel2TrackMode(54);
6713  Screen->Cursor = TCursor(-2); // Arrow
6714  Utilities->CallLogPop(1713);
6715  return;
6716  }
6718  Screen->Cursor = TCursor(-2); // Arrow
6719  Utilities->CallLogPop(1490);
6720  return;
6721  }
6722 
6723  else if(Level2TrackMode == GapSetting)
6724  {
6725  TrainController->LogEvent("mbLeft + GapSetting");
6726 // ResetChangedFileDataAndCaption(, true); moved to later after 2.7.0 in case can't set it
6727  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6728  // & it is highlighted
6729  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6730  {
6731  Utilities->CallLogPop(50);
6732  return; // true if finds one
6733  }
6734  ResetChangedFileDataAndCaption(11, true); // moved to here after 2.7.0 in case can't set it
6735  InfoPanel->Visible = true;
6736  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6737  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6738  Delay(0, 500); // 500 msec delay before next selection requested
6739 
6740  // ClearandRebuildRailway(8);//get rid of gap selections
6741  // need to call this later when new gap displayed, else old gap remains
6742 
6743  // now back to highlighting next gap
6744  // bool LocError = false;
6745  if(!(HighLightOneGap(1, HLoc, VLoc)))
6746  {
6747  // all gaps set
6748  ShowMessage("All gaps set");
6749  if(Level2TrackMode == AddTrack)
6750  {
6752  SetLevel1Mode(66);
6753  SetLevel2TrackMode(31);
6754  }
6755  else
6756  {
6758  SetLevel1Mode(37);
6759  }
6760  ClearandRebuildRailway(9); // get rid of last gap ellipse
6761  Utilities->CallLogPop(51);
6762  return;
6763  }
6764  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6765  // by another call to MainScreenMouseDown
6766  }
6767 
6768  else if(Level2TrackMode == AddText)
6769  {
6770  TrainController->LogEvent("mbLeft + AddText");
6771 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to TextBoxKeyPress in case nothing changed
6772  // X & Y are relative to Display output, but TextBox is placed relative to Form
6773  // if mouse position on first character of an existing piece of text reload it into the editor
6774 
6775  bool TextFoundFlag = false;
6776  int TrueX = 0, TrueY = 0;
6777  AnsiString ExistingText = "";
6779  TFont *ExistingTextFont = new TFont;
6780  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6781  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6782  if(!TextHandler->TextVector.empty())
6783  {
6784  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6785  {
6786  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6787  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6788  {
6789  ExistingText = TextPtr->TextString;
6790  ExistingTextFont->Assign(TextPtr->Font);
6791  ExistingTextHPos = TextPtr->HPos;
6792  ExistingTextVPos = TextPtr->VPos;
6793  TextFoundFlag = true;
6794  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6795  break;
6796  } // if ....
6797 
6798  } // for TextPtr...
6799  } // if !TextVector...
6800 
6801  if(TextFoundFlag)
6802  {
6803  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6804  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6805  TextBox->Font->Assign(ExistingTextFont);
6806  Display->SetFont(ExistingTextFont);
6807  Text_X = ExistingTextHPos;
6808  Text_Y = ExistingTextVPos;
6809  }
6810  else
6811  {
6812  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6813  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6814  TextBox->Font->Assign(Display->GetFont());
6815  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6816  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6817  }
6818  TextBox->Visible = true;
6819  TextBox->SetFocus();
6820  if(TextFoundFlag)
6821  {
6822  TextBox->Text = ExistingText;
6823  }
6824  else
6825  {
6826  TextBox->Text = "New Text: CR=end, ESC=quit";
6827  }
6828  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6829  TextBox->SelectAll();
6830  delete ExistingTextFont;
6831  ClearandRebuildRailway(29); // to remove old text if replaced
6833  Utilities->CallLogPop(1775);
6834  return; // If text input go no further
6835  }
6836 
6838  {
6839  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6840 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case nothing found
6841  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6842  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6843  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6844  // StartX = X + (Display->DisplayOffsetH * 16);
6845  // StartY = Y + (Display->DisplayOffsetV * 16);
6848  if(!TextFoundFlag) // give precedence to text
6849  {
6852  {
6853  ResetChangedFileDataAndCaption(13, true); // moved here after 2.7.0 to save only if something found
6854  }
6855  }
6856  else
6857  {
6858  ResetChangedFileDataAndCaption(27, true); // and here
6859  }
6860  Utilities->CallLogPop(53);
6861  return; // if text move selected don't permit anything else
6862  }
6863 
6864  else if(Level2TrackMode == TrackSelecting)
6865  /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6866  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6867  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6868  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6869  selected rectangle.
6870  */
6871  {
6872  TrainController->LogEvent("mbLeft + TrackSelecting");
6873  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6874  SelectStartPair.first = HLoc;
6875  SelectStartPair.second = VLoc;
6876  }
6877 
6878  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6879  /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6880  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6881  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6882  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6883  */
6884  {
6885  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6886 // ResetChangedFileDataAndCaption(, true); moved after 2.7.0 to later in case don't proceed
6887  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6888  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6889  {
6890  SelectPickedUp = false;
6891  Utilities->CallLogPop(54);
6892  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6893  }
6894  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6895  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6896  {
6897  SelectPickedUp = false;
6898  Utilities->CallLogPop(55);
6899  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6900  }
6901  else
6902  {
6903  SelectPickedUp = true;
6904  }
6905  ResetChangedFileDataAndCaption(14, true); // moved here after 2.7.0 in case don't proceed
6908  }
6909 
6911  {
6912  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6913 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6914 // RlyFile = false; - don't alter this just for PrefDir changes
6915  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6916  {
6917  ResetChangedFileDataAndCaption(15, false); // moved after 2.7.0 to here
6921  }
6922  Utilities->CallLogPop(56);
6923  return;
6924  }
6925 
6927  {
6928  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6929 // ResetChangedFileDataAndCaption(, false); //moved after 2.7.0 to later in case don't click on element
6930 // RlyFile = false; - don't alter this just for PrefDir changes
6931  bool FinishElement;
6932  Screen->Cursor = TCursor(-11); // Hourglass;
6933  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6934  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6935  {
6936  // not same as start element
6937  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6938  {
6940  ResetChangedFileDataAndCaption(16, false); // moved after 2.7.0 to here
6941  if(FinishElement)
6942  {
6943  ShowMessage("Preferred direction added");
6946  SetLevel1Mode(16);
6947  Screen->Cursor = TCursor(-2); // Arrow
6948  Utilities->CallLogPop(57);
6949  return;
6950  }
6951  else
6952  {
6955  }
6956  // set again since 1st time
6957  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6958  // to do the checks for Loop & End for each element as it is added
6959  }
6960  }
6961  else // same as start element
6962  {
6965  SetLevel1Mode(121);
6966  Screen->Cursor = TCursor(-2); // Arrow
6967  Utilities->CallLogPop(1714);
6968  return;
6969  }
6970  Screen->Cursor = TCursor(-2); // Arrow
6971  Utilities->CallLogPop(58);
6972  return;
6973  }
6974 
6976  {
6977  TrainController->LogEvent("mbLeft + PrefDirSelecting");
6978  ClearandRebuildRailway(56); // to get rid of earlier rectangles
6979  SelectStartPair.first = HLoc;
6980  SelectStartPair.second = VLoc;
6981  }
6982 
6983  else if(Level1Mode == OperMode)
6984  {
6985  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
6986  {
6987  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
6988  int Position;
6989  TTrackElement TrackElement;
6990  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
6991  {
6992  if(TrackElement.TrackType != SignalPost)
6993  {
6994  CallingOnButton->Down = false;
6995 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
6997  Utilities->CallLogPop(59);
6998  return;
6999  }
7000  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
7001  {
7003  {
7005  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
7007  {
7008  // found it!
7009 /*
7010  if(TrackElement.SpeedTag == 68)
7011  {
7012  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
7013  }
7014  if(TrackElement.SpeedTag == 69)
7015  {
7016  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
7017  }
7018  if(TrackElement.SpeedTag == 70)
7019  {
7020  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
7021  }
7022  if(TrackElement.SpeedTag == 71)
7023  {
7024  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
7025  }
7026  if(TrackElement.SpeedTag == 72)
7027  {
7028  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
7029  }
7030  if(TrackElement.SpeedTag == 73)
7031  {
7032  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
7033  }
7034  if(TrackElement.SpeedTag == 74)
7035  {
7036  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
7037  }
7038  if(TrackElement.SpeedTag == 75)
7039  {
7040  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
7041  }
7042 */
7043  Track->TrackElementAt(430, Position).CallingOnSet = true;
7044  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
7045 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
7046  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
7047  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
7050  CallingOnButton->Down = false;
7052 
7053 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
7054 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
7055 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
7056  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
7057  {
7058  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
7059  {
7060  // only allow route element to be removed if not selected for a route start otherwise
7061  // StartSelectionRouteID will be set & will fail at convert
7063  {
7065  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
7066  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
7067  AnsiString(PDE.VLoc));
7068  }
7069  }
7070  }
7071 
7072 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
7073  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
7074  {
7075  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
7076  {
7077  // found it
7078  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
7079  // if RouteOrPartRouteSet false then set an unrestricted route into platform
7080  {
7081  bool PointsChanged = false;
7082  IDInt ReqPosRouteID(-1);
7083  TOneRoute *NewRoute = new TOneRoute;
7084  bool CallonTrue = true;
7085  if(NewRoute->GetNonPreferredRouteStartElement(1,
7086  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
7087  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, CallonTrue))
7088  {
7089  if(NewRoute->GetNextNonPreferredRouteElement(1,
7090  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
7091  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, CallonTrue,
7092  ReqPosRouteID, PointsChanged))
7093  {
7094  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
7095  {
7096  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
7097  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
7098  }
7099  }
7100  }
7101  delete NewRoute;
7102  }
7103  }
7104  }
7105 // InfoPanel->Visible = false;
7106  Utilities->CallLogPop(60);
7107  return;
7108  }
7109  }
7110  }
7111  }
7112  CallingOnButton->Down = false;
7114  Utilities->CallLogPop(61);
7115  return;
7116  }
7117 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
7118  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
7119  If any of above conditions not met then treat as route selection, setting route flasher if
7120  route continuing.
7121 */
7122 
7123  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
7124  // disallow route setting if paused
7125  {
7126  if(Level2OperMode == PreStart)
7127  {
7128  PointsFlashDuration = 0.0;
7131  }
7132  else
7133  {
7134  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7135  if(TTClockSpeed < 1)
7136  {
7137  TempSpeedVal = TTClockSpeed;
7138  }
7139  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7142  }
7143  if(RouteMode == RouteNotStarted)
7144  {
7145  TrainController->LogEvent("mbLeft + RouteNotStarted");
7146  int Position;
7147  TTrackElement TrackElement;
7148  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
7149  {
7150  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
7152  // Flash selected points & changeover if appropriate
7153  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
7154  // to ensure user only does one thing at a time
7155  {
7156  if(TrackElement.TrainIDOnElement > -1)
7157  {
7158  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
7159  Utilities->CallLogPop(62);
7160  return;
7161  }
7162  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7163 
7164 /*
7165  This used to try to allow any linked trailing edges to cause both points to change, but no good if
7166  there are two adjacent crossovers, where both trailing edges are linked to two different points.
7167  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
7168  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
7169  ensures that there are no obscure links. Hence better to stick with original.
7170 
7171  //check if trailing edge linked to another point trailing edge
7172  int DivergingPosition = TrackElement.Conn[1];
7173  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
7174  DivergingPointVectorPosition = -1;
7175  if((DivergingElement.TrackType == Points) &&
7176  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7177  {
7178  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7179  {
7180  ShowMessage("Linked points Locked");
7181  }
7182  else DivergingPointVectorPosition = DivergingPosition;
7183  }
7184  else
7185  {
7186  DivergingPosition = TrackElement.Conn[3];
7187  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
7188  if((DivergingElement.TrackType == Points) &&
7189  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
7190  {
7191  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
7192  {
7193  ShowMessage("Linked points locked");
7194  }
7195  else DivergingPointVectorPosition = DivergingPosition;
7196  }
7197  }
7198  Track->PointFlashFlag = true;
7199  PointFlashVectorPosition = Position;
7200  PointFlashStartTime = TrainController->TTClockTime;
7201  [close curly bracket - if include it matches earlier non-commented one!]
7202 */
7203  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
7204  int DivergingPosition = TrackElement.Conn[3];
7205  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
7206  DivergingPosition))) // full match inc same attributes
7207  {
7208  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
7209  {
7210  TrainController->StopTTClockMessage(2, "Linked points locked");
7211  }
7212  else
7213  {
7214  Track->PointFlashFlag = true;
7215  PointFlashVectorPosition = Position;
7216  DivergingPointVectorPosition = DivergingPosition;
7218  }
7219  }
7220  else // no matching point, just change this point
7221  {
7222  Track->PointFlashFlag = true;
7223  PointFlashVectorPosition = Position;
7226  }
7227  }
7228 
7229  else if(Track->IsLCAtHV(59, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag)
7230  // level crossing added at v2.6.0 to allow manual LC changing
7231  {
7232  if(Track->GetInactiveTrackElementFromTrackMap(5, HLoc, VLoc).Attribute != 2) // 2 = LC changing state, can't click if changing
7233  {
7234  Track->LCChangeFlag = true;
7235  bool TrainPresent = false;
7236  if(Track->IsLCBarrierDownAtHV(4, HLoc, VLoc)) // if true then may be able to raise barriers
7237  {
7238  // first need to identify the LC in the BarriersDownVector
7239  int BDVectorPos = -1;
7240  if(Track->AnyLinkedBarrierDownVectorManual(1, HLoc, VLoc, BDVectorPos)) // looking for same position & manually closed
7241  {
7242  // this largely copied from ClockTimer2
7244  Track->BarriersDownVector.at(BDVectorPos).VLoc, ConstructRoute->SearchVector, TrainPresent))
7245  // returns true for route set or being set or train, and TrainPresent true if train on LC
7246  {
7247  TTrack::TActiveLevelCrossing CLC = Track->BarriersDownVector.at(BDVectorPos);
7248  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7249  TDateTime TempExcessLCDownTime;
7250  if(Track->BarriersDownVector.at(BDVectorPos).ReducedTimePenalty)
7251  // this set in ClockTimer2, relies on train being on LC for >= 1 second
7252  {
7253  // get the 3 mins allowance - hard to imagine will pass in less than a second!
7254  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7255  }
7256  else
7257  {
7258  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7259  }
7260  if(TempExcessLCDownTime > TDateTime(0))
7261  {
7262  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7263  }
7264  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7267  Track->SetLinkedLevelCrossingBarrierAttributes(7, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7268  Track->ChangingLCVector.push_back(CLC);
7269  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + BDVectorPos);
7270  }
7271  }
7272  }
7273  else // lowering
7274  {
7275  // this largely copied from SetLCChangeValues
7276  TTrack::TActiveLevelCrossing ALC; // constructor sets ReducedTimePenalty to false
7277  ALC.HLoc = HLoc;
7278  ALC.VLoc = VLoc;
7280  ALC.BaseElementSpeedTag = TrackElement.SpeedTag;
7283  ALC.TypeOfRoute = 2;
7284  Track->SetLinkedManualLCs(0, HLoc, VLoc);
7285 // this sets all linked LC ConsecSignals values to 2 for manually lowered - differs from SetLCChangeValues which uses the route type
7286  Track->SetLinkedLevelCrossingBarrierAttributes(6, HLoc, VLoc, 2); // set attr to 2 for changing state
7287  Track->ChangingLCVector.push_back(ALC);
7289  {
7290  AnsiString Message =
7291  AnsiString("This will open the level crossing manually (it will show in green).\n\nA manually opened"
7292  " level crossing must be manually closed, and as soon as possible to avoid time penalties.\n\n" "This message will not be shown again."
7293  );
7294  TrainController->StopTTClockMessage(93, Message);
7296  }
7297  }
7298  }
7299  }
7300  else // route start
7301  {
7302  if(AutoSigsFlag)
7303  {
7304  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7306  }
7307  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
7308  {
7309  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7311  }
7312  else
7313  {
7314  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7316  }
7317  if(PreferredRoute)
7318  {
7319  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7320  // another route building
7321  {
7322  ConstructRoute->ClearRoute(); // in case not empty though should be
7324  {
7325  if(AutoSigsFlag)
7326  {
7328  }
7329  else
7330  {
7332  }
7334  InfoPanel->Visible = true;
7335  if(Level2OperMode == PreStart)
7336  {
7337  InfoPanel->Caption = "PRE-START: Select next route location";
7338  }
7339  else
7340  {
7341  InfoPanel->Caption = "OPERATING: Select next route location";
7342  }
7343  }
7344  }
7345  Utilities->CallLogPop(63);
7346  return;
7347  }
7348  else // nonpreferred route
7349  {
7350  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7351  // another route building
7352  {
7353  ConstructRoute->ClearRoute(); // in case not empty though should be
7354  bool CallonFalse = false;
7355  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, CallonFalse))
7356  {
7359  InfoPanel->Visible = true;
7360  if(Level2OperMode == PreStart)
7361  {
7362  InfoPanel->Caption = "PRE-START: Select next route location";
7363  }
7364  else
7365  {
7366  InfoPanel->Caption = "OPERATING: Select next route location";
7367  }
7368  }
7369  }
7370  Utilities->CallLogPop(64);
7371  return;
7372  } // NonPreferred route
7373 
7374  } // TrackType != Points
7375 
7376  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
7377 
7378  } // if(RouteMode == RouteNotStarted)
7379  else // RouteContinuing
7380  {
7381  TrainController->LogEvent("mbLeft + RouteContinuing");
7382  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7385  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
7386  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
7387  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
7388  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
7389  // element, but this sets it to an hourglass while searching
7390  bool PointsChanged = false;
7391  if(PreferredRoute)
7392  {
7393  // route added to AllRoutes in GetNextRouteElement if valid
7394  // int ReqPosRouteNumber;
7396  ConstructRoute->ReqPosRouteID, PointsChanged))
7397  {
7398  Track->RouteFlashFlag = true;
7399  PreferredRouteFlag = true;
7400  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7401  if(TTClockSpeed < 1)
7402  {
7403  TempSpeedVal = TTClockSpeed;
7404  }
7405  if(Level2OperMode == PreStart)
7406  {
7407  RouteFlashDuration = 0.0;
7408  }
7409  else if(PointsChanged)
7410  {
7411  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7412  }
7413  else
7414  {
7415  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7416  }
7417  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for PrefDirRoute
7419  }
7420  else
7421  {
7423  }
7424  Screen->Cursor = TCursor(-2); // Arrow
7425  TrainController->BaseTime = TDateTime::CurrentDateTime();
7427  Utilities->CallLogPop(65);
7428  return;
7429  }
7430  else
7431  {
7432  bool CallonFalse = false;
7433  if(ConstructRoute->GetNextNonPreferredRouteElement(0, HLoc, VLoc, CallonFalse, ConstructRoute->ReqPosRouteID, PointsChanged))
7434  {
7435  Track->RouteFlashFlag = true;
7436  PreferredRouteFlag = false;
7437  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7438  if(TTClockSpeed < 1)
7439  {
7440  TempSpeedVal = TTClockSpeed;
7441  }
7442  if(Level2OperMode == PreStart)
7443  {
7444  RouteFlashDuration = 0.0;
7445  }
7446  else if(PointsChanged)
7447  {
7448  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7449  }
7450  else
7451  {
7452  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7453  }
7454  ConstructRoute->SetRouteFlashValues(2, false, false);
7456  }
7457  else
7458  {
7460  }
7461  }
7462  TrainController->BaseTime = TDateTime::CurrentDateTime();
7464  Screen->Cursor = TCursor(-2); // Arrow
7465  }
7466  Utilities->CallLogPop(66);
7467  return;
7468  }
7469  }
7470  Utilities->CallLogPop(68);
7471  }
7472  catch(const Exception &e)
7473  {
7474  ErrorLog(20, e.Message);
7475  }
7476 }
7477 
7478 // ---------------------------------------------------------------------------
7479 
7480 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
7481 // ZoomOut mode
7482 {
7483 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
7484  try
7485  {
7486  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7487  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
7488  "," + AnsiString(Y));
7489  if(Button != mbLeft)
7490  {
7491  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
7494  WholeRailwayMoving = true;
7495  Screen->Cursor = TCursor(-22); // Four arrows;
7496  }
7497  else
7498  {
7499  InfoPanel->Visible = false; // reset infopanel in case not set later
7500  InfoPanel->Caption = "";
7501  int HRounding, VRounding;
7502  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
7503  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
7504  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
7505  if(TruePosH < 0)
7506  {
7507  HRounding = -(Utilities->ScreenElementWidth / 4);
7508  }
7509  else
7510  {
7511  HRounding = (Utilities->ScreenElementWidth / 4);
7512  }
7513  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
7514  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
7515  {
7516  CentreH -= (Utilities->ScreenElementWidth / 2);
7517  }
7518  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
7519  {
7520  CentreH += (Utilities->ScreenElementWidth / 2);
7521  }
7522  if(TruePosV < 0)
7523  {
7524  VRounding = -(Utilities->ScreenElementHeight / 4);
7525  }
7526  else
7527  {
7528  VRounding = (Utilities->ScreenElementHeight / 4);
7529  }
7530  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
7531  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
7532  {
7533  CentreV -= (Utilities->ScreenElementHeight / 2);
7534  }
7535  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
7536  {
7537  CentreV += (Utilities->ScreenElementHeight / 2);
7538  }
7539  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
7541 
7542  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
7543  if(Level1Mode == BaseMode)
7544  {
7545  SetLevel1Mode(17);
7546  }
7547  else if(Level1Mode == TrackMode)
7548  {
7549  // set edit menu items
7551  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
7552  // displayed gap, user wants to display the clicked area
7553  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
7554  PreventGapOffsetResetting = false;
7555  }
7556  else if(Level1Mode == PrefDirMode)
7557  {
7559  {
7560  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
7561  }
7562  else
7563  {
7564  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
7565  }
7566  }
7567  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
7568  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
7569  else if(Level1Mode == TimetableMode)
7570  {
7571  InfoPanel->Visible = false;
7572  }
7573  // Not OperMode or RestartSessionOperMode as that resets the performance file
7574  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
7575  {
7576  OperateButton->Enabled = true;
7577  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
7578  ExitOperationButton->Enabled = true;
7580  }
7581  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
7582  {
7583  OperateButton->Enabled = true;
7584  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7585  ExitOperationButton->Enabled = true;
7586  TTClockAdjButton->Enabled = true;
7589  }
7590  else if(TempLevel2OperMode == PreStart)
7591  {
7592  OperateButton->Enabled = true;
7593  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7594  ExitOperationButton->Enabled = true;
7595  TTClockAdjButton->Enabled = true;
7597  }
7598  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7601  }
7602  Utilities->CallLogPop(69);
7603  }
7604  catch(const Exception &e)
7605  {
7606  ErrorLog(21, e.Message);
7607  }
7608 }
7609 
7610 // ---------------------------------------------------------------------------
7611 
7612 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7613 {
7614  try
7615  {
7616  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7617  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7618 
7619  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7620  {
7621  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7623  if(X < 0)
7624  {
7625  X = 0; // ensure pointer stays within display area
7626  }
7627  if(X > (MainScreen->Width - 1))
7628  {
7629  X = MainScreen->Width - 1;
7630  }
7631  if(Y < 0)
7632  {
7633  Y = 0;
7634  }
7635  if(Y > (MainScreen->Height - 1))
7636  {
7637  Y = MainScreen->Height - 1;
7638  }
7639  if(!Display->ZoomOutFlag)
7640  {
7641  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7642  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7643  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7644  {
7645  int NewH = X - StartWholeRailwayMoveHPos;
7646  int NewV = Y - StartWholeRailwayMoveVPos;
7647  Display->DisplayOffsetH -= NewH / 16;
7648  Display->DisplayOffsetV -= NewV / 16;
7649  StartWholeRailwayMoveHPos = X - StartOffsetX;
7650  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7653  {
7655  }
7656  }
7657  }
7658 
7659  else
7660  {
7661  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7662  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7663  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7664  {
7665  int NewH = X - StartWholeRailwayMoveHPos;
7666  int NewV = Y - StartWholeRailwayMoveVPos;
7667  Display->DisplayZoomOutOffsetH -= NewH / 4;
7668  Display->DisplayZoomOutOffsetV -= NewV / 4;
7669  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7670  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7671  Display->ClearDisplay(10);
7673  }
7674  }
7675  TrainController->BaseTime = TDateTime::CurrentDateTime();
7677  }
7678 
7679  else if(mbLeftDown)
7680  {
7682  /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7683  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7684  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7685  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7686  selected rectangle.
7687  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7688  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7689  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7690  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7691  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7692  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7693  the selection.
7694  */
7695  {
7696  if(!MMoveTrackSelFlag)
7697  {
7698  TrainController->LogEvent("MouseMove + TrackSelecting");
7699  MMoveTrackSelFlag = true;
7700  }
7701  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7702  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7703  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7704  // rightmost point and the VLoc value of the bottommost point
7705  if(CurrentHLoc >= StartHLoc)
7706  {
7707  CurrentHLoc++;
7708  }
7709  else
7710  {
7711  StartHLoc++;
7712  }
7713  if(CurrentVLoc >= StartVLoc)
7714  {
7715  CurrentVLoc++;
7716  }
7717  else
7718  {
7719  StartVLoc++;
7720  }
7721  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7722  {
7724  }
7725  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7726  {
7728  }
7729  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7730  {
7731  CurrentHLoc = Display->DisplayOffsetH;
7732  }
7733  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7734  {
7735  CurrentVLoc = Display->DisplayOffsetV;
7736  }
7737  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7738  ClearandRebuildRailway(14); // to clear earlier rectangles
7739  Display->PlotDashedRect(0, TempRect);
7740  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7741  }
7742 
7744  {
7745  if(!MMovePrefDirSelFlag)
7746  {
7747  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7748  MMovePrefDirSelFlag = true;
7749  }
7750 
7751  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7752  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7753  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7754  // rightmost point and the VLoc value of the bottommost point
7755  if(CurrentHLoc >= StartHLoc)
7756  {
7757  CurrentHLoc++;
7758  }
7759  else
7760  {
7761  StartHLoc++;
7762  }
7763  if(CurrentVLoc >= StartVLoc)
7764  {
7765  CurrentVLoc++;
7766  }
7767  else
7768  {
7769  StartVLoc++;
7770  }
7771  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7772  {
7774  }
7775  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7776  {
7778  }
7779  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7780  {
7781  CurrentHLoc = Display->DisplayOffsetH;
7782  }
7783  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7784  {
7785  CurrentVLoc = Display->DisplayOffsetV;
7786  }
7787  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7788  ClearandRebuildRailway(57); // to clear earlier rectangles
7789  Display->PlotDashedRect(2, TempRect);
7790  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7791  }
7792 
7794  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7795  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7796  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7797  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7798  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7799  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7800  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7801  occupies. Clearand... is called finally to clear earlier selection displays.
7802  */
7803  {
7805  {
7806  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7808  }
7809  if(X < 0)
7810  {
7811  X = 0; // ensure pointer stays within display area
7812  }
7813  if(X > (MainScreen->Width - 1))
7814  {
7815  X = MainScreen->Width - 1;
7816  }
7817  if(Y < 0)
7818  {
7819  Y = 0;
7820  }
7821  if(Y > (MainScreen->Height - 1))
7822  {
7823  Y = MainScreen->Height - 1;
7824  }
7827  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7828  }
7829 
7831  {
7833  {
7834  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7836  }
7838  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7840  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7841 
7842  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7843  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7845  }
7846 
7848  {
7850  {
7851  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7853  }
7855  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7857  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7858 
7862  }
7863  }
7864  Utilities->CallLogPop(70);
7865  }
7866  catch(const Exception &e)
7867  {
7868  ErrorLog(22, e.Message);
7869  }
7870 }
7871 
7872 // ---------------------------------------------------------------------------
7873 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7874 {
7875 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7876  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7877  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7878  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7879  selected rectangle.
7880  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7881  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7882  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7883  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7884  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7885  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7886  the selection.
7887  [New] This function can take some time so an hourglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7888  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7889  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7890  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7891  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7892  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7893  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7894  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7895  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7896  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7897  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7898  to an arrow.
7899 */
7900  try
7901  {
7902  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7903  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7904  WholeRailwayMoving = false; // added at v2.1.0
7905  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7906  MMoveTrackSelFlag = false;
7907  MMovePrefDirSelFlag = false;
7911 
7913  {
7914  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7915  Screen->Cursor = TCursor(-11); // Hourglass;
7916  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7917  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7918 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7919 // rightmost point and the VLoc value of the bottommost point
7920  if(EndHLoc >= StartHLoc)
7921  {
7922  EndHLoc++;
7923  }
7924  else
7925  {
7926  StartHLoc++;
7927  }
7928  if(EndVLoc >= StartVLoc)
7929  {
7930  EndVLoc++;
7931  }
7932  else
7933  {
7934  StartVLoc++;
7935  }
7936  if(StartHLoc >= EndHLoc)
7937  {
7938  SelectRect.left = EndHLoc;
7939  SelectRect.right = StartHLoc;
7940  }
7941  else
7942  {
7943  SelectRect.left = StartHLoc;
7944  SelectRect.right = EndHLoc;
7945  }
7946  if(StartVLoc >= EndVLoc)
7947  {
7948  SelectRect.top = EndVLoc;
7949  SelectRect.bottom = StartVLoc;
7950  }
7951  else
7952  {
7953  SelectRect.top = StartVLoc;
7954  SelectRect.bottom = EndVLoc;
7955  }
7957  {
7959  }
7961  {
7963  }
7964  if(SelectRect.left - Display->DisplayOffsetH < 0)
7965  {
7967  }
7968  if(SelectRect.top - Display->DisplayOffsetV < 0)
7969  {
7971  }
7972  Level2TrackMode = AddTrack; // Level1Mode must be TrackMode
7973  SetLevel2TrackMode(69); // add all track elements so area can be filled with an element, must come before PlotDashedRect as calls Clearand...
7974  Level2TrackMode = TrackSelecting; // reset from AddTrack
7978  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7979  {
7980  SelectionValid = false;
7982  mbLeftDown = false;
7983  Screen->Cursor = TCursor(-2); // Arrow;
7984  Utilities->CallLogPop(71);
7985  return; // no rectangle
7986  }
7987  else
7988  {
7989  ReselectMenuItem->Enabled = false;
7990  CutMenuItem->Enabled = true;
7991  CopyMenuItem->Enabled = true;
7992  FlipMenuItem->Enabled = true;
7993  MirrorMenuItem->Enabled = true;
7994  RotRightMenuItem->Enabled = true;
7995  RotLeftMenuItem->Enabled = true;
7996  RotateMenuItem->Enabled = true;
7997 
7998 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting (dropped at 2.4.0 as all pastes are with attributes)
7999  DeleteMenuItem->Enabled = true;
8000  if(Track->IsTrackFinished())
8001  {
8002  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8003  }
8004  else
8005  {
8006  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8007  }
8008  SelectBiDirPrefDirsMenuItem->Visible = false;
8009  CheckPrefDirConflictsMenuItem->Visible = false;
8010  CancelSelectionMenuItem->Enabled = true;
8011  // set SelectBitmap
8012  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
8013  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
8014 
8015  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
8016  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
8017  {
8018  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
8019  {
8020  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
8021  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
8022  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
8023  }
8024  }
8025 
8027  TTrackElement TempElement; // default element
8028  bool FoundFlag;
8029  //store active elements
8030  for(int x = SelectRect.left; x < SelectRect.right; x++)
8031  {
8032  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8033  {
8034  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
8035  if(FoundFlag)
8036  {
8037  TempElement = Track->TrackElementAt(440, ATVecPos);
8038  if(TempElement.SpeedTag > 0)
8039  {
8040  Track->SelectPush(TempElement); // don't store erase elements
8041  }
8042  }
8043  }
8044  }
8045  // now store inactive elements
8046  for(int x = SelectRect.left; x < SelectRect.right; x++)
8047  {
8048  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8049  {
8050  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
8051  if(FoundFlag)
8052  {
8053  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
8054  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
8055  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
8056  {
8057  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
8058  Track->SelectPush(TempElement);
8059  }
8060  }
8061  }
8062  }
8063 
8064  //store preferred directions //added at v2.9.0
8065  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
8066  TPrefDirElement TempPrefDirElement;
8068  for(int x = SelectRect.left; x < SelectRect.right; x++)
8069  {
8070  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8071  {
8072  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(11, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
8073  if(FoundFlag)
8074  {
8075  if(PrefDirPos0 > -1)
8076  {
8077  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(2, PrefDirPos0);
8078  SelectPrefDir->ExternalStorePrefDirElement(6, TempPrefDirElement);
8079  }
8080  if(PrefDirPos1 > -1)
8081  {
8082  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(3, PrefDirPos1);
8083  SelectPrefDir->ExternalStorePrefDirElement(7, TempPrefDirElement);
8084  }
8085  if(PrefDirPos2 > -1)
8086  {
8087  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(4, PrefDirPos2);
8088  SelectPrefDir->ExternalStorePrefDirElement(8, TempPrefDirElement);
8089  }
8090  if(PrefDirPos3 > -1)
8091  {
8092  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(5, PrefDirPos3);
8093  SelectPrefDir->ExternalStorePrefDirElement(9, TempPrefDirElement);
8094  }
8095  }
8096  }
8097  }
8098 
8099  // store text items
8100  int LowSelectHPos = SelectRect.left * 16;
8101  int HighSelectHPos = SelectRect.right * 16;
8102  int LowSelectVPos = SelectRect.top * 16;
8103  int HighSelectVPos = SelectRect.bottom * 16;
8104  TextHandler->SelectTextVector.clear();
8105  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
8106  {
8107  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
8108  {
8109  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
8110  HighSelectVPos))
8111  {
8112  // have to create a new TextItem in order to create a new Font object
8113  // BUT: only create new items where they don't appear as named location names
8114  // in SelectVector, since those names shouldn't be copied or pasted.
8115  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
8116  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
8117  bool SelectVectorNamedElement = false;
8118  AnsiString SelectTextString; // new at v2.2.0
8119  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
8120  {
8121  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
8122  {
8123  SelectVectorNamedElement = true;
8124  break;
8125  }
8126  }
8127  if(SelectVectorNamedElement) // changed at v2.2.0
8128  {
8129  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
8130  }
8131  else // new at v2.2.0
8132  {
8133  SelectTextString = TextPtr->TextString;
8134  }
8135  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
8136  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
8137  }
8138  }
8139  }
8140  // store graphic items, but first clear SelectGraphicVector
8141  Track->SelectGraphicVector.clear();
8142  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
8143  {
8144  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
8145  UserGraphicPtr++)
8146  {
8147  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
8148  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
8149  {
8150  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
8151  }
8152  }
8153  }
8154 // new method - direct copying of existing selection so text included
8155  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8156  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8157  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8158  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8159  SelectionValid = true;
8160  }
8161  Screen->Cursor = TCursor(-2); // Arrow;
8162  }
8163 
8165  {
8166  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
8167  Screen->Cursor = TCursor(-11); // Hourglass;
8168 
8169  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
8170  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
8171 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
8172 // rightmost point and the VLoc value of the bottommost point
8173  if(EndHLoc >= StartHLoc)
8174  {
8175  EndHLoc++;
8176  }
8177  else
8178  {
8179  StartHLoc++;
8180  }
8181  if(EndVLoc >= StartVLoc)
8182  {
8183  EndVLoc++;
8184  }
8185  else
8186  {
8187  StartVLoc++;
8188  }
8189  if(StartHLoc >= EndHLoc)
8190  {
8191  SelectRect.left = EndHLoc;
8192  SelectRect.right = StartHLoc;
8193  }
8194  else
8195  {
8196  SelectRect.left = StartHLoc;
8197  SelectRect.right = EndHLoc;
8198  }
8199  if(StartVLoc >= EndVLoc)
8200  {
8201  SelectRect.top = EndVLoc;
8202  SelectRect.bottom = StartVLoc;
8203  }
8204  else
8205  {
8206  SelectRect.top = StartVLoc;
8207  SelectRect.bottom = EndVLoc;
8208  }
8210  {
8212  }
8214  {
8216  }
8217  if(SelectRect.left - Display->DisplayOffsetH < 0)
8218  {
8220  }
8221  if(SelectRect.top - Display->DisplayOffsetV < 0)
8222  {
8224  }
8228  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
8229  {
8231  mbLeftDown = false;
8232  Screen->Cursor = TCursor(-2); // Arrow;
8233  Utilities->CallLogPop(1551);
8234  return; // no rectangle
8235  }
8236  else
8237  {
8238  SelectBiDirPrefDirsMenuItem->Enabled = true;
8239  CheckPrefDirConflictsMenuItem->Enabled = false;
8240  CancelSelectionMenuItem->Enabled = true;
8241  // don't need SelectBitmap for PrefDir selection
8242 
8243  // store active elements in Track->SelectVector, ignore inactive elements
8244  // clear the vector first
8246  TTrackElement TempElement; // default element
8247  bool FoundFlag;
8248  for(int x = SelectRect.left; x < SelectRect.right; x++)
8249  {
8250  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8251  {
8252  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
8253  if(FoundFlag)
8254  {
8255  TempElement = Track->TrackElementAt(729, ATVecPos);
8256  if(TempElement.SpeedTag > 0)
8257  {
8258  Track->SelectPush(TempElement); // don't store erase elements
8259  }
8260  }
8261  }
8262  }
8263  }
8264  Screen->Cursor = TCursor(-2); // Arrow;
8265  }
8266 
8268  /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
8269  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
8270  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
8271  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
8272  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
8273  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
8274  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
8275  occupies. Clearand... is called finally to clear earlier selection displays.
8276  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
8277  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
8278  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
8279  */
8280  {
8281  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
8284  }
8285  mbLeftDown = false;
8286  Track->CalcHLocMinEtc(11);
8287  Utilities->CallLogPop(72);
8288  }
8289  catch(const Exception &e)
8290  {
8291  ErrorLog(23, e.Message);
8292  }
8293 }
8294 
8295 // ---------------------------------------------------------------------------
8296 
8297 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
8298 {
8299  try
8300  {
8301  // don't call LogEvent here as would occur too often
8302  // have to allow in zoomout mode
8303  if(ErrorLogCalledFlag)
8304  {
8305  return; // don't continue after an error
8306 
8307  }
8308  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
8309  // put counter outside Clock2 as that may be missed
8310  LCResetCounter++;
8311 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
8312  if(LCResetCounter > 19)
8313  {
8314  LCResetCounter = 0;
8315  }
8317  if(WarningFlashCount > 4)
8318  {
8319  WarningFlashCount = 0;
8320  }
8321  if(WarningFlashCount == 0)
8322  {
8324  }
8325  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
8326  {
8327  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
8328  }
8330  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
8331  {
8332  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
8333  // BaseTime is CurrentDateTime() when operation restarts
8334 
8335 // clock speed multiplier
8336  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
8337  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
8338 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
8339  }
8340  TotalTicks++;
8342  {
8343  MissedTicks++;
8344  Utilities->CallLogPop(774);
8345  return;
8346  }
8347  Utilities->Clock2Stopped = true; // don't allow overlapping calls
8348  ClockTimer2(0);
8349  Utilities->Clock2Stopped = false;
8350  Utilities->CallLogPop(73);
8351  }
8352  catch(const Exception &e)
8353  {
8354  ErrorLog(24, e.Message);
8355  }
8356 }
8357 
8358 // ---------------------------------------------------------------------------
8359 
8360 void TInterface::ClockTimer2(int Caller)
8361 {
8362 // called every 50mSec
8363  try
8364  {
8365  // have to allow in zoomout mode
8366  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
8367 
8368  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
8369  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
8370 
8371 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
8372  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
8373  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
8374 
8375  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
8376 
8377  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
8378  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
8379  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
8380  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
8381 
8382  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
8383  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
8384  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
8385  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
8386  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
8387  {
8388  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
8389  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
8390  if(ClockTimer2Count == 0)
8391  {
8392  RestoreFocusPanel->Visible = true;
8393  RestoreFocusPanel->Enabled = true;
8394  RestoreFocusPanel->BringToFront();
8395  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
8396  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
8397  RestoreFocusPanel->Visible = false;
8398  }
8399  }
8400  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
8401 */
8402 
8403  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
8404  // toggled by 'Ctrl Alt 2' when Interface form has focus
8405 
8406  // set current time
8407  TDateTime Now = TrainController->TTClockTime;
8408 
8409  if(!OAListBox->MouseInClient) // added at v2.7.0 to reset this flag whenever mouse not in OAListBox
8410  {
8412  }
8413  if(!ClipboardChecked)
8414  {
8415  if((Level1Mode == TrackMode) && !SelectionValid & (ClpBrdValid != "RlyClpBrd_Cut") && (ClpBrdValid != "RlyClpBrdCopy"))
8416  // reset the menu for the new app (when !SelectionValid) & don't keep resetting when ClpBrdValid
8417  {
8418  SetTrackModeEditMenu(2); // to reset the menu in case select a new app for pasting
8419  ClipboardChecked = true;
8420  }
8421  }
8425  {
8427  }
8428  if(OperatorActionPanel->Visible)
8429  {
8431  }
8434  {
8435  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
8436  }
8437  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
8439  {
8441  }
8442 // Update Displayed Clock - resets to 0 at 96hours
8444 
8445 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
8446 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
8447 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
8448  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
8449  {
8450  WholeRailwayMoving = false;
8451  Screen->Cursor = TCursor(-2); // Arrow
8452  }
8453 // save session if required
8454  if(SaveSessionFlag)
8455  {
8456  SaveSession(0);
8457  SaveSessionFlag = false;
8458  }
8459 // load session if required
8460  if(LoadSessionFlag)
8461  {
8462  if(ClearEverything(3))
8463  {
8464  LoadSession(0);
8465  }
8466  LoadSessionFlag = false;
8467  }
8468 // check if any LCs need barriers raising
8469 
8471  {
8473  {
8474  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--) // iterate downwards because erase element
8475  {
8476  bool TrainPresent = false;
8478  Track->BarriersDownVector.at(x).VLoc, ConstructRoute->SearchVector, TrainPresent)) // returns true for route (set or being set) or train, and TrainPresent true if train on LC
8479  {
8480  if(TrainPresent)
8481  {
8482  Track->BarriersDownVector.at(x).ReducedTimePenalty = true;
8483 // to allow 3 mins before time penalty starts to clock up, if no train passes then no time allowance
8484  }
8485  }
8486  else
8487  {
8488  if(Track->BarriersDownVector.at(x).TypeOfRoute != 2) // added at v2.6.0 for manual LC operation
8489  {
8490  Track->LCChangeFlag = true;
8492  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
8493  TDateTime TempExcessLCDownTime;
8494  if(Track->BarriersDownVector.at(x).ReducedTimePenalty)
8495  {
8496  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
8497  }
8498  else
8499  {
8500  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
8501  }
8502  if(TempExcessLCDownTime > TDateTime(0))
8503  {
8504  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
8505  }
8506  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
8509  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
8510  Track->ChangingLCVector.push_back(CLC);
8511  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
8512  }
8513  }
8514  }
8515  }
8516  }
8517 // clear LCChangeFlag if no LCs changing
8518  if(Track->ChangingLCVector.empty())
8519  {
8520  Track->LCChangeFlag = false;
8521  }
8522 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
8523 // element it may be removed prior to conversion & cause an error
8524 
8525 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
8526 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
8527 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
8528 // this, it shouldn't interfere with operation.
8530  {
8531  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
8532  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
8533  {
8534  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
8535  {
8536  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
8537  // set & will fail at convert
8539  {
8541  // also don't remove if it links two automatic signal routes (reported by Daniel Gill for Darlington via discord on 13/12/20)
8542  // added at v2.6.1
8543  // note that a train will still remove the route element when it reaches it because of the 3rd condition below, but it will be removed when the train
8544  // is half on the preceding element rather than fully on it, in other cases the train has to be fully on the element because the route only becomes a
8545  // single element at that stage
8546  unsigned int LinkFromTVNumber = Track->TrackElementAt(1007, PDE.GetTrackVectorPosition()).Conn[PDE.GetELinkPos()];
8547  unsigned int LinkToTVNumber = Track->TrackElementAt(1008, PDE.GetTrackVectorPosition()).Conn[PDE.GetXLinkPos()];
8548  int RouteNumber1, RouteNumber2, TrainID; // not used
8549  if((AllRoutes->GetRouteTypeAndNumber(37, LinkFromTVNumber, PDE.GetELinkPos(), RouteNumber1) != TAllRoutes::AutoSigsRoute) ||
8550  (AllRoutes->GetRouteTypeAndNumber(38, LinkToTVNumber, PDE.GetXLinkPos(), RouteNumber2) != TAllRoutes::AutoSigsRoute) ||
8551  (Track->TrackElementAt(1009, LinkFromTVNumber).TrainIDOnElement > -1))
8552  // don't need to test for it being a bridge as then LinkFromTVNumber can't be
8553  // an autosigs route
8554  {
8555  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
8556  ElementRemovedFlag = true;
8557  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
8558  }
8559  }
8560  }
8561  }
8562  if(!Display->ZoomOutFlag && ElementRemovedFlag)
8563  {
8565  }
8566  // if zoomed out ignore, will display correctly when zoom in
8567  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
8568  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
8569  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
8570  }
8571 // stop clock if hover over a warning
8572  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
8573  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
8574  && OutputLog1->Caption != "";
8575  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
8576  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
8577  && OutputLog2->Caption != "";
8578  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
8579  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
8580  && OutputLog3->Caption != "";
8581  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
8582  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
8583  && OutputLog4->Caption != "";
8584  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
8585  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
8586  && OutputLog5->Caption != "";
8587  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
8588  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
8589  && OutputLog6->Caption != "";
8590  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
8591  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
8592  && OutputLog7->Caption != "";
8593  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
8594  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
8595  && OutputLog8->Caption != "";
8596  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
8597  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
8598  && OutputLog9->Caption != "";
8599  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
8600  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
8601  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
8602 
8603  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
8604  {
8605  if(!WarningHover)
8606  {
8607  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
8609  WarningHover = true;
8610  }
8611  }
8612  else if(WarningHover)
8613  {
8614  WarningHover = false;
8615  TrainController->BaseTime = TDateTime::CurrentDateTime();
8617  }
8618 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
8619  if(DevelopmentPanel->Visible)
8620  {
8621  int Position;
8622  TTrackElement TrackElement;
8623  AnsiString Type[15] =
8624  {
8625  "Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
8626  "Parapet", "NamedNonStationLocation", "Erase"
8627  };
8628 
8629  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
8630  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
8631  int HLoc, VLoc;
8632  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
8633  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
8634  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
8635  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
8636  {
8637  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
8638  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
8639  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
8640  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
8641  TrackElement.ActiveTrackElementName;
8642 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
8643  }
8644  }
8645  if(Level1Mode == TimetableMode)
8646  {
8647 /* These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
8648 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version at v2.5.0 for details.
8649 
8650 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
8651 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
8652 the entry that the mouse is now on rather than the one that was chosen.
8653 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
8654 */
8655  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0))
8656  // high order bit set to 1 when button down, so arithmetically it is negative
8657  {
8658  // TTCurrentEntryPtr == 0 when create a timetable
8659  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
8660  }
8661  if(AnyTTKeyFlagSet()) // true if any of the below flags set
8662  {
8663  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; // reset it to the value before the key press changes it (see FormKeyDown)
8664  }
8666  {
8667  PreviousTTEntryButton->Click();
8668  SetTopIndex(0);
8669  PreviousTTEntryKeyFlag = false;
8670  }
8671  else if(NextTTEntryKeyFlag)
8672  {
8673  NextTTEntryButton->Click();
8674  SetTopIndex(1);
8675  NextTTEntryKeyFlag = false;
8676  }
8677  else if(MoveTTEntryUpKeyFlag)
8678  {
8679  MoveTTEntryUpButton->Click();
8680  SetTopIndex(2);
8681  MoveTTEntryUpKeyFlag = false;
8682  }
8683  else if(MoveTTEntryDownKeyFlag)
8684  {
8685  MoveTTEntryDownButton->Click();
8686  SetTopIndex(3);
8687  MoveTTEntryDownKeyFlag = false;
8688  }
8689  else if(CopyTTEntryKeyFlag)
8690  {
8691  CopyTTEntryButton->Click();
8692  SetTopIndex(4);
8693  CopyTTEntryKeyFlag = false;
8694  }
8695  else if(CutTTEntryKeyFlag)
8696  {
8697  CutTTEntryButton->Click();
8698  SetTopIndex(5);
8699  CutTTEntryKeyFlag = false;
8700  }
8701  else if(PasteTTEntryKeyFlag)
8702  {
8703  PasteTTEntryButton->Click();
8704  SetTopIndex(6);
8705  PasteTTEntryKeyFlag = false;
8706  }
8707  else if(DeleteTTEntryKeyFlag)
8708  {
8709  DeleteTTEntryButton->Click();
8710  SetTopIndex(7);
8711  DeleteTTEntryKeyFlag = false;
8712  }
8713  else if(NewTTEntryKeyFlag)
8714  {
8715  NewTTEntryButton->Click();
8716  SetTopIndex(8);
8717  NewTTEntryKeyFlag = false;
8718  }
8719  else if(AZOrderKeyFlag)
8720  {
8721  AZOrderButton->Click();
8722  SetTopIndex(9);
8723  AZOrderKeyFlag = false;
8724  }
8726  {
8727  TTServiceSyntaxCheckButton->Click();
8728  SetTopIndex(12);
8730  }
8731  else if(ValidateTimetableKeyFlag)
8732  {
8733  ValidateTimetableButton->Click();
8734  SetTopIndex(13);
8735  ValidateTimetableKeyFlag = false;
8736  }
8737  else if(SaveTTKeyFlag)
8738  {
8739  SaveTTButton->Click();
8740  SetTopIndex(14);
8741  SaveTTKeyFlag = false;
8742  }
8743  else if(SaveTTAsKeyFlag)
8744  {
8745  SaveTTAsButton->Click();
8746  SetTopIndex(15);
8747  SaveTTAsKeyFlag = false;
8748  }
8749  else if(RestoreTTKeyFlag)
8750  {
8751  RestoreTTButton->Click();
8752  SetTopIndex(16);
8753  RestoreTTKeyFlag = false;
8754  }
8755  else if(ExportTTKeyFlag)
8756  {
8757  ExportTTButton->Click();
8758  SetTopIndex(17);
8759  ExportTTKeyFlag = false;
8760  }
8761  else if(ConflictAnalysisKeyFlag)
8762  {
8763  ConflictAnalysisButton->Click();
8764  SetTopIndex(18);
8765  ConflictAnalysisKeyFlag = false;
8766  }
8767 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
8768  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
8769  {
8771  }
8772  else
8773  {
8775  }
8776  }
8777 // set cursor
8779  {
8780  if(!TempCursorSet)
8781  {
8782  TempCursor = Screen->Cursor;
8783  TempCursorSet = true;
8784  }
8785  Screen->Cursor = TCursor(-11); // Hourglass
8786  }
8787  else
8788  {
8789  if(TempCursorSet)
8790  {
8791  Screen->Cursor = TempCursor;
8792  TempCursorSet = false;
8793  }
8794  }
8795  if(Level2OperMode == Operating)
8796  {
8797  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8798  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8800  {
8801  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8802  }
8803  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8804  }
8805 
8806  else if(Level2OperMode == Paused) // added at v2.5.0 to show actions due after a session file reloaded
8807  {
8809  {
8810  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8811  {
8813  }
8816  }
8817  }
8818 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
8819 // by examining Flash
8820  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
8821  {
8823  }
8824 //deal with any manual LCs with barriers down in zoomout mode - these flash as reminder that need to re-open
8825 
8827  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
8828  {
8829  if((Track->BarriersDownVector.at(x).BarrierState == TTrack::Down) && (Track->BarriersDownVector.at(x).TypeOfRoute == 2))
8830  {
8831  //manual crossing down, but maybe a route across it
8832  bool TrainPresent; //not used outside function
8834  ConstructRoute->SearchVector, TrainPresent)) //no warning raised if a route or train present
8835  {
8838  {
8840  RailGraphics->smLC, Display); //smLC
8841  }
8842  else if((WarningFlashCount == 0) && !WarningFlash && Display->ZoomOutFlag)
8843  {
8845  RailGraphics->smSolidBgnd, Display); //SMOrange
8846  }
8847  }
8848  }
8849  }
8850 
8851 // Deal with any flashing graphics
8853  {
8854  FlashingGraphics(0, Now); // only call when WarningFlash changes
8855  if(Level1Mode == OperMode)
8856  {
8857  if(WarningFlash)
8858  {
8860  {
8861  CrashImage->Visible = true;
8862  }
8864  {
8865  DerailImage->Visible = true;
8866  }
8868  {
8869  SPADImage->Visible = true;
8870  }
8872  {
8873  TrainFailedImage->Visible = true;
8874  }
8876  {
8877  CallOnImage->Visible = true;
8878  }
8880  {
8881  SignalStopImage->Visible = true;
8882  }
8884  {
8885  BufferAttentionImage->Visible = true;
8886  }
8887  if(ManualLCDownAttentionWarning) //added at v2.9.0
8888  {
8889  ManualLCDownImage->Visible = true;
8890  }
8891  }
8892  else
8893  {
8894  CrashImage->Visible = false;
8895  DerailImage->Visible = false;
8896  SPADImage->Visible = false;
8897  TrainFailedImage->Visible = false;
8898  CallOnImage->Visible = false;
8899  SignalStopImage->Visible = false;
8900  BufferAttentionImage->Visible = false;
8901  ManualLCDownImage->Visible = false;
8902  }
8903  }
8904  else
8905  {
8906  CrashImage->Visible = false;
8907  DerailImage->Visible = false;
8908  SPADImage->Visible = false;
8909  TrainFailedImage->Visible = false;
8910  CallOnImage->Visible = false;
8911  SignalStopImage->Visible = false;
8912  BufferAttentionImage->Visible = false;
8914  }
8915  } // if(WarningFlashCount == 0)
8916 
8917  // set buttons etc as appropriate
8919  // if forced route cancellation flag set redisplay to clear the cancelled route
8921  {
8923  AllRoutes->RebuildRailwayFlag = false;
8924  }
8925  // deal with approach locking
8927  // deal with ContinuationAutoSigList
8929  // FloatingLabel function
8930  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
8931  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
8932  {
8933  TrackTrainFloat(0);
8934  }
8935  else
8936  {
8937  FloatingPanel->Visible = false;
8938  }
8939  // PerformanceLog check function
8940 /*
8941  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
8942  {
8943  PerformancePanel->Visible = false;
8944  }
8945  else
8946  {
8947 */
8949  {
8950  PerformancePanel->Visible = true;
8951  }
8952  else
8953  {
8954  PerformancePanel->Visible = false;
8955  }
8957  {
8958  OperatorActionPanel->Visible = true;
8959  }
8960  else
8961  {
8962  OperatorActionPanel->Visible = false;
8963  }
8964 // }
8965 
8966  // check if a moving train is present on a route-under-construction start element & cancel it if so
8967  if(RouteMode == RouteContinuing)
8968  {
8969  bool FoundFlag;
8970  int RouteStartVecPos;
8971  if(AutoSigsFlag)
8972  {
8974  FoundFlag);
8975  }
8976  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
8977  {
8978  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
8979  FoundFlag);
8980  }
8981  else
8982  {
8984  FoundFlag);
8985  }
8986  if(FoundFlag && (RouteStartVecPos > -1))
8987  {
8988  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
8989  if(TrackElement.TrainIDOnElement > -1)
8990  {
8991  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
8992  {
8994  // replot train as above erases the front element of the train
8996  }
8997  }
8998  }
8999  }
9000  Utilities->CallLogPop(81);
9001  }
9002  catch(const Exception &e)
9003  {
9004  ErrorLog(25, e.Message);
9005  }
9006 }
9007 
9008 // ---------------------------------------------------------------------------
9009 
9010 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
9011 {
9012  try
9013  {
9014  TrainController->LogEvent("CallingOnButtonClick");
9015  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
9016  if(CallingOnButton->Down)
9017  {
9018  // CallingOnButton->Down = true;
9019  InfoPanel->Visible = true;
9020  InfoPanel->Caption = "CALLING ON: Select signal for call on";
9021  }
9022  else
9023  {
9024  // CallingOnButton->Down = false;
9026  }
9027  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
9028  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
9029  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
9030  CallingOnButton->Enabled = false;
9031 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
9032  Utilities->CallLogPop(82);
9033  }
9034  catch(const Exception &e)
9035  {
9036  ErrorLog(26, e.Message);
9037  }
9038 }
9039 
9040 // ---------------------------------------------------------------------------
9041 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
9042 {
9043  try
9044  {
9045  // have to allow in zoomout mode
9046  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9047  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9048  Screen->Cursor = TCursor(-11); // Hourglass;
9049  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9050  if(!Display->ZoomOutFlag)
9051  {
9052  if(CtrlKey)
9053  {
9054  Display->DisplayOffsetH -= 2;
9055  }
9056  else if(ShiftKey)
9057  {
9059  }
9060  else
9061  {
9063  }
9066  {
9068  }
9069  }
9070  else
9071  {
9072  if(CtrlKey)
9073  {
9075  }
9076  else if(ShiftKey)
9077  {
9079  }
9080  else
9081  {
9083  }
9084  Display->ClearDisplay(0);
9087  {
9088  Track->PlotSmallRedGap(0);
9089  }
9090  }
9091  ScreenLeftButton->Enabled = true;
9092  Screen->Cursor = TCursor(-2); // Arrow
9093  Utilities->CallLogPop(83);
9094  }
9095  catch(const Exception &e)
9096  {
9097  ErrorLog(27, e.Message);
9098  }
9099 }
9100 // ---------------------------------------------------------------------------
9101 
9102 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
9103 {
9104  try
9105  {
9106  // have to allow in zoomout mode
9107  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9108  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9109  Screen->Cursor = TCursor(-11); // Hourglass;
9110  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9111  if(!Display->ZoomOutFlag)
9112  {
9113  if(CtrlKey)
9114  {
9115  Display->DisplayOffsetH += 2;
9116  }
9117  else if(ShiftKey)
9118  {
9120  }
9121  else
9122  {
9124  }
9127  {
9129  }
9130  }
9131  else
9132  {
9133  if(CtrlKey)
9134  {
9136  }
9137  else if(ShiftKey)
9138  {
9140  }
9141  else
9142  {
9144  }
9145  Display->ClearDisplay(1);
9148  {
9149  Track->PlotSmallRedGap(1);
9150  }
9151  }
9152  ScreenRightButton->Enabled = true;
9153  Screen->Cursor = TCursor(-2); // Arrow
9154  Utilities->CallLogPop(84);
9155  }
9156  catch(const Exception &e)
9157  {
9158  ErrorLog(28, e.Message);
9159  }
9160 }
9161 // ---------------------------------------------------------------------------
9162 
9163 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
9164 {
9165  try
9166  {
9167  // have to allow in zoomout mode
9168  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9169  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9170  Screen->Cursor = TCursor(-11); // Hourglass;
9171  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9172  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
9173  if(!Display->ZoomOutFlag)
9174  {
9175  if(CtrlKey)
9176  {
9177  Display->DisplayOffsetV += 2;
9178  }
9179  else if(ShiftKey)
9180  {
9182  }
9183  else
9184  {
9186  }
9189  {
9191  }
9192  }
9193  else
9194  {
9195  if(CtrlKey)
9196  {
9198  }
9199  else if(ShiftKey)
9200  {
9202  }
9203  else
9204  {
9206  }
9207  Display->ClearDisplay(2);
9210  {
9211  Track->PlotSmallRedGap(2);
9212  }
9213  }
9214  ScreenDownButton->Enabled = true;
9215  Screen->Cursor = TCursor(-2); // Arrow
9216  Utilities->CallLogPop(85);
9217  }
9218  catch(const Exception &e)
9219  {
9220  ErrorLog(29, e.Message);
9221  }
9222 }
9223 // ---------------------------------------------------------------------------
9224 
9225 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
9226 {
9227  try
9228  {
9229  // have to allow in zoomout mode
9230  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9231  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
9232  Screen->Cursor = TCursor(-11); // Hourglass;
9233  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
9234  if(!Display->ZoomOutFlag)
9235  {
9236  if(CtrlKey)
9237  {
9238  Display->DisplayOffsetV -= 2;
9239  }
9240  else if(ShiftKey)
9241  {
9243  }
9244  else
9245  {
9247  }
9250  {
9252  }
9253  }
9254  else
9255  {
9256  if(CtrlKey)
9257  {
9259  }
9260  else if(ShiftKey)
9261  {
9263  }
9264  else
9265  {
9267  }
9268  Display->ClearDisplay(3);
9271  {
9272  Track->PlotSmallRedGap(3);
9273  }
9274  }
9275  ScreenUpButton->Enabled = true;
9276  Screen->Cursor = TCursor(-2); // Arrow
9277  Utilities->CallLogPop(86);
9278  }
9279  catch(const Exception &e)
9280  {
9281  ErrorLog(30, e.Message);
9282  }
9283 }
9284 // ---------------------------------------------------------------------------
9285 
9286 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
9287 {
9288  try
9289  {
9290  // have to allow in zoomout mode
9291  TrainController->LogEvent("ZoomButtonClick");
9292  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
9293  Screen->Cursor = TCursor(-11); // Hourglass;
9294  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9295  if(Display->ZoomOutFlag) // i.e resume zoomed in view
9296  {
9297  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
9298 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
9299  if(Level1Mode == BaseMode)
9300  {
9301  InfoPanel->Visible = false; // reset infopanel in case not set later
9302  InfoPanel->Caption = "";
9303  SetLevel1Mode(18);
9304  }
9305  else if(Level1Mode == TrackMode)
9306  {
9307  InfoPanel->Visible = false; // reset infopanel in case not set later
9308  InfoPanel->Caption = "";
9309  // set edit menu items
9311  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
9312  }
9313  else if(Level1Mode == PrefDirMode)
9314  {
9316  {
9317  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
9318  }
9319  else
9320  {
9321  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
9322  }
9323  }
9324 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
9325 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
9326  else if(Level1Mode == TimetableMode)
9327  {
9328  InfoPanel->Visible = false;
9329  }
9330  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
9331  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
9332  {
9333  OperateButton->Enabled = true;
9334  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
9335  ExitOperationButton->Enabled = true;
9337  }
9338  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
9339  {
9340  OperateButton->Enabled = true;
9341  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9342  ExitOperationButton->Enabled = true;
9343  TTClockAdjButton->Enabled = true;
9346  }
9347  else if(Level2OperMode == PreStart)
9348  {
9349  OperateButton->Enabled = true;
9350  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
9351  ExitOperationButton->Enabled = true;
9352  TTClockAdjButton->Enabled = true;
9354  }
9355  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
9357  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
9358  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
9359  }
9360  else // set zoomed out view
9361  {
9362  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
9363  Display->ZoomOutFlag = true;
9365  FileMenu->Enabled = false;
9366  ModeMenu->Enabled = false;
9367  EditMenu->Enabled = false;
9368  TextBox->Visible = false;
9369  LocationNameTextBox->Visible = false;
9370  TTClockAdjButton->Enabled = false;
9371 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
9372  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9373  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
9374 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
9375  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
9376  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
9377  if((LeftExcess > 0) && (RightExcess > 0))
9378  {
9379  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
9380  }
9381  else if((LeftExcess > 0) && (RightExcess <= 0))
9382  {
9383  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
9384  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
9385  }
9386  else if((LeftExcess <= 0) && (RightExcess > 0))
9387  {
9388  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
9389  }
9390  else
9391  {
9392  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
9393 
9394  }
9395  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
9396  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
9397  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
9398  if((TopExcess > 0) && (BotExcess > 0))
9399  {
9400  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
9401  }
9402  else if((TopExcess > 0) && (BotExcess <= 0))
9403  {
9404  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
9405  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
9406  }
9407  else if((TopExcess <= 0) && (BotExcess > 0))
9408  {
9409  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
9410  }
9411  else
9412  {
9413  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
9414 
9415  }
9416  Display->ClearDisplay(4);
9420  {
9421  Track->PlotSmallRedGap(4);
9422  }
9423  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
9424  }
9425  Screen->Cursor = TCursor(-2); // Arrow
9426  ZoomButton->Enabled = true; // restore, see above
9427  Utilities->CallLogPop(87);
9428  }
9429  catch(const Exception &e)
9430  {
9431  ErrorLog(31, e.Message);
9432  }
9433 }
9434 // ---------------------------------------------------------------------------
9435 
9436 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
9437 {
9438  try
9439  {
9440  // have to allow in zoomout mode
9441  TrainController->LogEvent("HomeButtonClick");
9442  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
9443  Screen->Cursor = TCursor(-11); // Hourglass;
9444  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9445  if(!Display->ZoomOutFlag) // zoomed in mode
9446  {
9447  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
9451  {
9453  }
9454  }
9455  else
9456  {
9457  // zoomed out mode
9458  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
9459  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
9461  Display->ClearDisplay(9);
9464  {
9465  Track->PlotSmallRedGap(5);
9466  }
9467  }
9468  Screen->Cursor = TCursor(-2); // Arrow
9469  HomeButton->Enabled = true; // restore, see above
9470  Utilities->CallLogPop(88);
9471  }
9472  catch(const Exception &e)
9473  {
9474  ErrorLog(32, e.Message);
9475  }
9476 }
9477 
9478 // ---------------------------------------------------------------------------
9479 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
9480 {
9481  try
9482  {
9483  TrainController->LogEvent("NewHomeButtonClick");
9484  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
9485  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
9486  if(!Display->ZoomOutFlag) // zoomed in mode
9487  {
9490  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
9491  }
9492  else
9493  {
9496  }
9497  Utilities->CallLogPop(1188);
9498  NewHomeButton->Enabled = true; // restore, see above
9499  }
9500  catch(const Exception &e)
9501  {
9502  ErrorLog(174, e.Message);
9503  }
9504 }
9505 
9506 // ---------------------------------------------------------------------------
9507 void __fastcall TInterface::EditMenuClick(TObject *Sender)
9508 // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
9509 {
9510  try
9511  {
9512  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
9513  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
9514  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
9515  }
9516  catch(const Exception &e)
9517  {
9518  ErrorLog(196, e.Message);
9519  }
9520 }
9521 
9522 // ---------------------------------------------------------------------------
9523 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
9524 {
9525 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
9526  try
9527  {
9528  TrainController->LogEvent("SelectMenuItemClick");
9529  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
9530  if(Level1Mode == TrackMode)
9531  {
9532  SelectionValid = false;
9534  SetLevel2TrackMode(34);
9536  {
9537  ShowMessage("Please be aware when pasting that anything inside the pasted area will be overwritten.\n\nThis warning will not be shown again.");
9538  PasteWarningSentFlag = true;
9539  }
9540  }
9541  else if(Level1Mode == PrefDirMode)
9542  {
9545  }
9546  Utilities->CallLogPop(1189);
9547  }
9548  catch(const Exception &e)
9549  {
9550  ErrorLog(145, e.Message);
9551  }
9552 }
9553 
9554 // ---------------------------------------------------------------------------
9555 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
9556 {
9557  try
9558  {
9559  TrainController->LogEvent("ReselectMenuItemClick");
9560  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
9561  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
9562  {
9563  Utilities->CallLogPop(1424);
9564  return;
9565  }
9566  int TLHCH = SelectBitmapHLoc;
9567  int TLHCV = SelectBitmapVLoc;
9568  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
9569  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
9570  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
9571  SelectRect = NewSelectRect;
9573  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
9574  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
9575  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
9576  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
9577  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
9578 
9579  SelectionValid = true;
9580  ReselectMenuItem->Enabled = false;
9581  CutMenuItem->Enabled = true;
9582  CopyMenuItem->Enabled = true;
9583  FlipMenuItem->Enabled = true;
9584  MirrorMenuItem->Enabled = true;
9585  RotRightMenuItem->Enabled = true;
9586  RotLeftMenuItem->Enabled = true;
9587  RotateMenuItem->Enabled = true;
9588  PasteMenuItem->Enabled = false;
9589  DeleteMenuItem->Enabled = true;
9590  if(Track->IsTrackFinished())
9591  {
9592  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
9593  }
9594  else
9595  {
9596  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
9597  }
9598  SelectBiDirPrefDirsMenuItem->Visible = false;
9599  CheckPrefDirConflictsMenuItem->Visible = false;
9600  CancelSelectionMenuItem->Enabled = true;
9601  mbLeftDown = false;
9602  // Level1Mode = TrackMode;
9603  // SetLevel1Mode(68);
9605  SetLevel2TrackMode(47);
9606  Utilities->CallLogPop(1425);
9607  }
9608  catch(const Exception &e)
9609  {
9610  ErrorLog(146, e.Message);
9611  }
9612 }
9613 
9614 // ---------------------------------------------------------------------------
9615 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
9616 {
9617  try
9618  {
9619  TrainController->LogEvent("CutMenuItemClick");
9620  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
9621  // Level1Mode = TrackMode;
9622  // SetLevel1Mode(69);
9623  CopySelected = false; // new at v2.8.0
9624  LoadClipboard(0); // new at v2.8.0
9626  SetLevel2TrackMode(35);
9627  Utilities->CallLogPop(1190);
9628  }
9629  catch(const Exception &e)
9630  {
9631  ErrorLog(147, e.Message);
9632  }
9633 }
9634 // ---------------------------------------------------------------------------
9635 
9636 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
9637 {
9638  try
9639  {
9640  TrainController->LogEvent("CopyMenuItemClick");
9641  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
9642  // Level1Mode = TrackMode;
9643  // SetLevel1Mode(70);
9644  CopySelected = true; // new at v2.8.0
9645  LoadClipboard(1); // new at v2.8.0
9647  SetLevel2TrackMode(36);
9648  Utilities->CallLogPop(1191);
9649  }
9650  catch(const Exception &e)
9651  {
9652  ErrorLog(148, e.Message);
9653  }
9654 }
9655 
9656 // ---------------------------------------------------------------------------
9657 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
9658 {
9659  try
9660  {
9661  TrainController->LogEvent("FlipMenuItemClick");
9662  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
9663  // reset values in SelectVector
9664  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9665  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9666  {
9667  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
9668  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
9669  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
9670  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
9671  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
9672  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
9673  int HLoc = Track->SelectVectorAt(7, x).HLoc;
9675  TE.VLoc = VLoc;
9676  TE.HLoc = HLoc;
9677 
9678  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9680  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
9681  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
9684  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
9685  Track->SelectVectorAt(26, x) = TE;
9686  }
9687 
9688  int FlipLinkArray[10] =
9689  {
9690  0, 7, 8, 9, 4, 5, 6, 1, 2, 3
9691  }; //0 & 5 are never used
9692 
9693  TrainController->LogEvent("Flip-track ok");
9694  // now reset the pref dirs
9695  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9696  {
9697  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9698  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9699  int VLoc = VerSum - SelectPrefDir->PrefDirVector.at(x).VLoc;
9700  int HLoc = SelectPrefDir->PrefDirVector.at(x).HLoc;
9701  int ELink = FlipLinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9702  int XLink = FlipLinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9704  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9705  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9706  TPrefDirElement PDE(TE); //this has Link[4]
9707  PDE.HLoc = HLoc;
9708  PDE.VLoc = VLoc;
9709  PDE.SetELink(ELink);
9710  PDE.SetXLink(XLink);
9711  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9712  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9713  {
9714  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9715  {
9716  PDE.SetELinkPos(y);
9717  ELinkPosFound = true;
9718  }
9719  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9720  {
9721  PDE.SetXLinkPos(y);
9722  XLinkPosFound = true;
9723  }
9724  }
9725  //set the CheckCount as before - added at v2.9.1
9726  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
9729 
9730  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
9731  bool FoundFlag = false;
9732  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(61, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
9733  if(PDE.GetSignedIntTrackVectorPosition() < 0)
9734  {
9735  FoundFlag = false; //probably will be anyway but reset to be sure & test below
9736  }
9738  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
9739  {
9741  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
9742  break;
9743  }
9744  SelectPrefDir->PrefDirVector.at(x) = PDE;
9745  }
9746 
9747  TrainController->LogEvent("Flip-prefdirs ok");
9748  // reset values in SelectTextVector
9749  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
9750  {
9752  // also subtract font height, brings position approximately right
9753  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9754  }
9755  TrainController->LogEvent("Flip-text ok");
9756  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9757  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9758  {
9759  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9760  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9761  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9762  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9763  }
9765  SetLevel2TrackMode(48);
9766  Utilities->CallLogPop(1426);
9767  }
9768  catch(const Exception &e)
9769  {
9770  ErrorLog(149, e.Message);
9771  }
9772 }
9773 
9774 // ---------------------------------------------------------------------------
9775 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
9776 {
9777  try
9778  {
9779  TrainController->LogEvent("MirrorMenuItemClick");
9780  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
9781  // reset values in SelectVector
9782  int HorSum = SelectRect.left + SelectRect.right - 1;
9783  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9784  {
9785  // See note above for FlipMenuItem relating to mods for v2.2.0
9786  int VLoc = Track->SelectVectorAt(22, x).VLoc;
9787  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
9789  TE.VLoc = VLoc;
9790  TE.HLoc = HLoc;
9791 
9792  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9794  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
9795  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
9798  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
9799 
9800 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
9801  Track->SelectVectorAt(30, x) = TE;
9802 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
9803 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
9804  }
9805 
9806  int MirrorLinkArray[10] =
9807  {
9808  0, 3, 2, 1, 6, 5, 4, 9, 8, 7
9809  }; //0 & 5 are never used
9810 
9811  TrainController->LogEvent("Mirror-track ok");
9812  // now reset the pref dirs
9813  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9814  {
9815  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9816  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9817  int HLoc = HorSum - SelectPrefDir->PrefDirVector.at(x).HLoc;
9818  int VLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9819  int ELink = MirrorLinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9820  int XLink = MirrorLinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9822  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9823  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9824  TPrefDirElement PDE(TE); //this has Link[4]
9825  PDE.HLoc = HLoc;
9826  PDE.VLoc = VLoc;
9827  PDE.SetELink(ELink);
9828  PDE.SetXLink(XLink);
9829  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9830  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9831  {
9832  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9833  {
9834  PDE.SetELinkPos(y);
9835  ELinkPosFound = true;
9836  }
9837  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9838  {
9839  PDE.SetXLinkPos(y);
9840  XLinkPosFound = true;
9841  }
9842  }
9843  //set the CheckCount as before - added at v2.9.1
9844  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
9847  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
9848  bool FoundFlag = false;
9849  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(62, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
9850  if(PDE.GetSignedIntTrackVectorPosition() < 0)
9851  {
9852  FoundFlag = false; //probably will be anyway but reset to be sure & test below
9853  }
9855  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
9856  {
9858  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
9859  break;
9860  }
9861  SelectPrefDir->PrefDirVector.at(x) = PDE;
9862  }
9863 
9864  TrainController->LogEvent("Mirror-PDs ok");
9865  // reset values in SelectTextVector
9866  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
9867  {
9869  // also subtract half font height for each letter of text, brings position approximately right
9870  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9871  }
9872  TrainController->LogEvent("Mirror-text ok");
9873  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
9874  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9875  {
9876  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
9877  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
9878  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
9879  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
9880  {
9881  LeftPosAfterMirror = SelectRect.left * 16;
9882  }
9883  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
9884  }
9886  SetLevel2TrackMode(49);
9887  Utilities->CallLogPop(1427);
9888  }
9889  catch(const Exception &e)
9890  {
9891  ErrorLog(150, e.Message);
9892  }
9893 }
9894 
9895 // ---------------------------------------------------------------------------
9896 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
9897 {
9898  try
9899  {
9900  TrainController->LogEvent("Rotate180MenuItemClick");
9901  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
9902 
9903  // reset values in SelectVector
9904  int HorSum = SelectRect.left + SelectRect.right - 1;
9905  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9906  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9907  {
9908  // See note above for FlipMenuItem relating to mods for v2.2.0
9909  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
9910  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
9912  TE.VLoc = VLoc;
9913  TE.HLoc = HLoc;
9914 
9915  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9917  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
9918  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
9921  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
9922 
9923 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
9924  Track->SelectVectorAt(34, x) = TE;
9925 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
9926 // TempEl.HLoc = HorSum - TempEl.HLoc;
9927 // TempEl.VLoc = VerSum - TempEl.VLoc;
9928 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
9929  }
9930 
9931  int Rot180LinkArray[10] =
9932  {
9933  0, 9, 8, 7, 6, 5, 4, 3, 2, 1
9934  }; //0 & 5 are never used
9935  TrainController->LogEvent("Rotate-track ok");
9936  // now reset the pref dirs
9937  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
9938  {
9939  int OriginalHLoc = SelectPrefDir->PrefDirVector.at(x).HLoc; //added at v2.9.1
9940  int OriginalVLoc = SelectPrefDir->PrefDirVector.at(x).VLoc;
9941  int HLoc = HorSum - SelectPrefDir->PrefDirVector.at(x).HLoc;
9942  int VLoc = VerSum - SelectPrefDir->PrefDirVector.at(x).VLoc;
9943  int ELink = Rot180LinkArray[SelectPrefDir->PrefDirVector.at(x).GetELink()];
9944  int XLink = Rot180LinkArray[SelectPrefDir->PrefDirVector.at(x).GetXLink()];
9946  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
9947  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
9948  TPrefDirElement PDE(TE); //this has Link[4]
9949  PDE.HLoc = HLoc;
9950  PDE.VLoc = VLoc;
9951  PDE.SetELink(ELink);
9952  PDE.SetXLink(XLink);
9953  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
9954  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
9955  {
9956  if(!ELinkPosFound && (PDE.Link[y] == ELink))
9957  {
9958  PDE.SetELinkPos(y);
9959  ELinkPosFound = true;
9960  }
9961  if(!XLinkPosFound && (PDE.Link[y] == XLink))
9962  {
9963  PDE.SetXLinkPos(y);
9964  XLinkPosFound = true;
9965  }
9966  }
9967  //set the CheckCount as before - added at v2.9.1
9968  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
9971  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
9972  bool FoundFlag = false;
9973  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(63, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
9974  if(PDE.GetSignedIntTrackVectorPosition() < 0)
9975  {
9976  FoundFlag = false; //probably will be anyway but reset to be sure & test below
9977  }
9979  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
9980  {
9982  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
9983  break;
9984  }
9985  SelectPrefDir->PrefDirVector.at(x) = PDE;
9986  }
9987  TrainController->LogEvent("Rotate-PDs ok");
9988  // reset values in SelectTextVector
9989  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
9990  {
9992  // also subtract half font height for each letter of text, brings position approximately right horizontally
9993  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9994  // also subtract font height, brings position approximately right vertically
9995  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9996  }
9997  TrainController->LogEvent("Rotate-text ok");
9998  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9999  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10000  {
10001  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
10002  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
10003  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
10004  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
10005  {
10006  TopPosAfterFlip = SelectRect.top * 16;
10007  }
10008  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
10009  }
10010  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
10011  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10012  {
10013  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
10014  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
10015  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
10016  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
10017  {
10018  LeftPosAfterMirror = SelectRect.left * 16;
10019  }
10020  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
10021  }
10022  // Level1Mode = TrackMode;
10023  // SetLevel1Mode(73);
10025  SetLevel2TrackMode(50);
10026  Utilities->CallLogPop(1435);
10027  }
10028  catch(const Exception &e)
10029  {
10030  ErrorLog(151, e.Message);
10031  }
10032 }
10033 // ---------------------------------------------------------------------------
10034 
10035 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
10036 {
10037  try
10038  {
10039  TrainController->LogEvent("RotateRightMenuItemClick");
10040  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRightMenuItemClick");
10041  Screen->Cursor = TCursor(-11); // Hourglass
10042  // check first if a square and if not give message & quit
10043  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
10044  {
10045  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
10046  int VertSize = SelectRect.bottom - SelectRect.top;
10047  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
10048  {
10049  // use right hand vertical & make square to left of that
10050  SelectRect.left = SelectRect.right - VertSize;
10051  }
10052  else
10053  {
10054  SelectRect.right = SelectRect.left + VertSize;
10055  }
10058  int button = Application->MessageBox
10059  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
10060  L"Left click and hold here to move this message box", MB_OKCANCEL);
10061  if(button == IDCANCEL)
10062  {
10063  ResetSelectRect();
10064  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
10065  SetLevel1Mode(133);
10067  SetLevel2TrackMode(59);
10069  Screen->Cursor = TCursor(-2); // Arrow
10070  Utilities->CallLogPop(2121);
10071  return;
10072  }
10073  }
10074  // set SelectBitmap (only need the dimensions here as not moving the selection)
10077  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
10078  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
10079 
10080  // store track elements and text in select vectors - have to store here because original selection might well have changed
10082  TTrackElement TempElement; // default element
10083  bool FoundFlag;
10084  for(int x = SelectRect.left; x < SelectRect.right; x++)
10085  {
10086  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10087  {
10088  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
10089  if(FoundFlag)
10090  {
10091  TempElement = Track->TrackElementAt(959, ATVecPos);
10092  if(TempElement.SpeedTag > 0)
10093  {
10094  Track->SelectPush(TempElement);
10095  }
10096  }
10097  }
10098  }
10099  // now store inactive elements
10100  for(int x = SelectRect.left; x < SelectRect.right; x++)
10101  {
10102  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10103  {
10104  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
10105  if(FoundFlag)
10106  {
10107  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
10108  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
10109  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
10110  {
10111  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
10112  Track->SelectPush(TempElement);
10113  }
10114  }
10115  }
10116  }
10117  TrainController->LogEvent("RotRight-trackstore ok");
10118  //store preferred directions //added at v2.9.0
10119  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10120  TPrefDirElement TempPrefDirElement;
10122  for(int x = SelectRect.left; x < SelectRect.right; x++)
10123  {
10124  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10125  {
10126  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(12, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10127  if(FoundFlag)
10128  {
10129  if(PrefDirPos0 > -1)
10130  {
10131  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(6, PrefDirPos0);
10132  SelectPrefDir->ExternalStorePrefDirElement(12, TempPrefDirElement);
10133  }
10134  if(PrefDirPos1 > -1)
10135  {
10136  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(7, PrefDirPos1);
10137  SelectPrefDir->ExternalStorePrefDirElement(13, TempPrefDirElement);
10138  }
10139  if(PrefDirPos2 > -1)
10140  {
10141  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(8, PrefDirPos2);
10142  SelectPrefDir->ExternalStorePrefDirElement(14, TempPrefDirElement);
10143  }
10144  if(PrefDirPos3 > -1)
10145  {
10146  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(9, PrefDirPos3);
10147  SelectPrefDir->ExternalStorePrefDirElement(15, TempPrefDirElement);
10148  }
10149  }
10150  }
10151  }
10152  TrainController->LogEvent("RotRight-PDstore ok");
10153  // store text items
10154  int LowSelectHPos = SelectRect.left * 16;
10155  int HighSelectHPos = SelectRect.right * 16;
10156  int LowSelectVPos = SelectRect.top * 16;
10157  int HighSelectVPos = SelectRect.bottom * 16;
10158  TextHandler->SelectTextVector.clear();
10159  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
10160  {
10161  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
10162  {
10163  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
10164  {
10165  // have to create a new TextItem in order to create a new Font object
10166  // BUT: only create new items where they don't appear as named location names
10167  // in SelectVector, since those names shouldn't be copied or pasted.
10168  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
10169  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
10170  bool SelectVectorNamedElement = false;
10171  AnsiString SelectTextString; // new at v2.2.0
10172  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
10173  {
10174  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
10175  {
10176  SelectVectorNamedElement = true;
10177  break;
10178  }
10179  }
10180  if(SelectVectorNamedElement) // changed at v2.2.0
10181  {
10182  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
10183  }
10184  else // new at v2.2.0
10185  {
10186  SelectTextString = TextPtr->TextString;
10187  }
10188  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
10189  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
10190  }
10191  }
10192  }
10193  TrainController->LogEvent("RotRight-textstore ok");
10194  // store graphic items, but first clear SelectGraphicVector
10195  Track->SelectGraphicVector.clear();
10196  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
10197  {
10198  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10199  UserGraphicPtr++)
10200  {
10201  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10202  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10203  {
10204  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10205  }
10206  }
10207  }
10208  TrainController->LogEvent("RotRight-graphicstore ok");
10209  // now transform the H & V for rh rotate
10210  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10211  {
10212  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
10213  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
10215  TE.VLoc = VLoc;
10216  TE.HLoc = HLoc;
10217 
10218  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10220  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
10221  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
10224  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
10225  Track->SelectVectorAt(65, x) = TE;
10226  }
10227 
10228  int RotRightLinkArray[10] =
10229  {
10230  0, 3, 6, 9, 2, 5, 8, 1, 4, 7
10231  }; //0 & 5 are never used
10232  TrainController->LogEvent("RotRight-trackrotate ok");
10233  // now transform the pref dirs
10234  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10235  {
10236  int OriginalHLoc = SelectPrefDir->GetFixedPrefDirElementAt(250, x).HLoc; //added at v2.9.1
10237  int OriginalVLoc = SelectPrefDir->GetFixedPrefDirElementAt(251, x).VLoc;
10238  int HLoc = SelectRect.bottom - 1 + SelectRect.left - OriginalVLoc;
10239  int VLoc = SelectRect.top - SelectRect.left + OriginalHLoc;
10240  int ELink = RotRightLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(252, x).GetELink()];
10241  int XLink = RotRightLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(253, x).GetXLink()];
10243  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10244  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10245  TPrefDirElement PDE(TE); //this has Link[4]
10246  PDE.HLoc = HLoc;
10247  PDE.VLoc = VLoc;
10248  PDE.SetELink(ELink);
10249  PDE.SetXLink(XLink);
10250  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10251  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10252  {
10253  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10254  {
10255  PDE.SetELinkPos(y);
10256  ELinkPosFound = true;
10257  }
10258  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10259  {
10260  PDE.SetXLinkPos(y);
10261  XLinkPosFound = true;
10262  }
10263  }
10264  //set the CheckCount as before - added at v2.9.1
10265  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10268  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10269  bool FoundFlag = false;
10270  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(64, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10271  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10272  {
10273  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10274  }
10276  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10277  {
10279  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10280  break;
10281  }
10282  SelectPrefDir->PrefDirVector.at(x) = PDE;
10283  }
10284  TrainController->LogEvent("RotRight-PDrotate ok");
10285  // reset values in SelectTextVector
10286  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
10287  {
10288 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10289 // & if a lot then some will extend beyond the selection
10291  // also subtract half font height for each letter of text, brings position approximately right horizontally
10292  TextItem->HPos = (SelectRect.left) * 16;
10293  TextItem->VPos = (SelectRect.top + x) * 16;
10294  }
10295  TrainController->LogEvent("RotRight-textrotate ok");
10296  // reset values in SelectGraphicVector
10297  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10298  {
10299  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10300  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10301  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
10302  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
10303  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10304  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10305  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10306  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10307  }
10308  Screen->Cursor = TCursor(-2); // Arrow
10310  SetLevel2TrackMode(60);
10311  Utilities->CallLogPop(2122);
10312  }
10313  catch(const Exception &e)
10314  {
10315  ErrorLog(205, e.Message);
10316  }
10317 }
10318 
10319 // ---------------------------------------------------------------------------
10320 
10321 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
10322 {
10323  try
10324  {
10325  TrainController->LogEvent("RotateLeftMenuItemClick");
10326  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeftMenuItemClick");
10327  Screen->Cursor = TCursor(-11); // Hourglass;
10328  // check first if a square and if not give message & quit
10329  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
10330  {
10331  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
10332  int VertSize = SelectRect.bottom - SelectRect.top;
10333  if((SelectRect.left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
10334  {
10335  // use right hand vertical & make square to left of that
10336  SelectRect.left = SelectRect.right - VertSize;
10337  }
10338  else
10339  {
10340  SelectRect.right = SelectRect.left + VertSize;
10341  }
10344  int button = Application->MessageBox
10345  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
10346  L"Left click and hold here to move this message box", MB_OKCANCEL);
10347  if(button == IDCANCEL)
10348  {
10349  ResetSelectRect();
10350  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
10351  SetLevel1Mode(134);
10353  SetLevel2TrackMode(61);
10355  Screen->Cursor = TCursor(-2); // Arrow
10356  Utilities->CallLogPop(2123);
10357  return;
10358  }
10359  }
10360  // set SelectBitmap (only need the dimensions here as not moving the selection)
10363  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
10364  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
10365 
10366  // store track elements and text in select vectors - have to store here because original selection might well have changed
10368  TTrackElement TempElement; // default element
10369  bool FoundFlag;
10370  for(int x = SelectRect.left; x < SelectRect.right; x++)
10371  {
10372  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10373  {
10374  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
10375  if(FoundFlag)
10376  {
10377  TempElement = Track->TrackElementAt(960, ATVecPos);
10378  if(TempElement.SpeedTag > 0)
10379  {
10380  Track->SelectPush(TempElement);
10381  }
10382  }
10383  }
10384  }
10385  // now store inactive elements
10386  for(int x = SelectRect.left; x < SelectRect.right; x++)
10387  {
10388  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10389  {
10390  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
10391  if(FoundFlag)
10392  {
10393  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
10394  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
10395  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
10396  {
10397  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
10398  Track->SelectPush(TempElement);
10399  }
10400  }
10401  }
10402  }
10403  TrainController->LogEvent("RotLeft-trackstore ok");
10404  //store preferred directions //added at v2.9.0
10405  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
10406  TPrefDirElement TempPrefDirElement;
10408  for(int x = SelectRect.left; x < SelectRect.right; x++)
10409  {
10410  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
10411  {
10412  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(13, x, y, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
10413  if(FoundFlag)
10414  {
10415  if(PrefDirPos0 > -1)
10416  {
10417  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(10, PrefDirPos0);
10418  SelectPrefDir->ExternalStorePrefDirElement(16, TempPrefDirElement);
10419  }
10420  if(PrefDirPos1 > -1)
10421  {
10422  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(11, PrefDirPos1);
10423  SelectPrefDir->ExternalStorePrefDirElement(17, TempPrefDirElement);
10424  }
10425  if(PrefDirPos2 > -1)
10426  {
10427  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(12, PrefDirPos2);
10428  SelectPrefDir->ExternalStorePrefDirElement(18, TempPrefDirElement);
10429  }
10430  if(PrefDirPos3 > -1)
10431  {
10432  TempPrefDirElement = EveryPrefDir->GetModifiablePrefDirElementAt(13, PrefDirPos3);
10433  SelectPrefDir->ExternalStorePrefDirElement(19, TempPrefDirElement);
10434  }
10435  }
10436  }
10437  }
10438  TrainController->LogEvent("RotLeft-PDstore ok");
10439  // store text items
10440  int LowSelectHPos = SelectRect.left * 16;
10441  int HighSelectHPos = SelectRect.right * 16;
10442  int LowSelectVPos = SelectRect.top * 16;
10443  int HighSelectVPos = SelectRect.bottom * 16;
10444  TextHandler->SelectTextVector.clear();
10445  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
10446  {
10447  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
10448  {
10449  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
10450  {
10451  // have to create a new TextItem in order to create a new Font object
10452  // BUT: only create new items where they don't appear as named location names
10453  // in SelectVector, since those names shouldn't be copied or pasted.
10454  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
10455  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
10456  bool SelectVectorNamedElement = false;
10457  AnsiString SelectTextString; // new at v2.2.0
10458  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
10459  {
10460  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
10461  {
10462  SelectVectorNamedElement = true;
10463  break;
10464  }
10465  }
10466  if(SelectVectorNamedElement) // changed at v2.2.0
10467  {
10468  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
10469  }
10470  else // new at v2.2.0
10471  {
10472  SelectTextString = TextPtr->TextString;
10473  }
10474  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
10475  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
10476  }
10477  }
10478  }
10479  TrainController->LogEvent("RotLeft-textstore ok");
10480  // store graphic items, but first clear SelectGraphicVector
10481  Track->SelectGraphicVector.clear();
10482  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
10483  {
10484  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
10485  UserGraphicPtr++)
10486  {
10487  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
10488  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
10489  {
10490  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
10491  }
10492  }
10493  }
10494  TrainController->LogEvent("RotLeft-graphicstore ok");
10495  // now transform the H & V for lh rotate
10496  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10497  {
10498  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
10499  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
10501  TE.VLoc = VLoc;
10502  TE.HLoc = HLoc;
10503 
10504  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
10506  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
10507  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
10510  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
10511  Track->SelectVectorAt(73, x) = TE;
10512  }
10513 
10514  int RotLeftLinkArray[10] =
10515  {
10516  0, 7, 4, 1, 8, 5, 2, 9, 6, 3
10517  }; //0 & 5 are never used
10518  TrainController->LogEvent("RotLeft-trackrotate ok");
10519  // now transform the pref dirs
10520  for(unsigned int x = 0; x < SelectPrefDir->PrefDirSize(); x++)
10521  {
10522  int OriginalHLoc = SelectPrefDir->GetFixedPrefDirElementAt(255, x).HLoc; //added at v2.9.1
10523  int OriginalVLoc = SelectPrefDir->GetFixedPrefDirElementAt(256, x).VLoc;
10524  int HLoc = SelectRect.left - SelectRect.top + OriginalVLoc;
10525  int VLoc = SelectRect.bottom - 1 + SelectRect.left - OriginalHLoc;
10526  int ELink = RotLeftLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(257, x).GetELink()];
10527  int XLink = RotLeftLinkArray[SelectPrefDir->GetFixedPrefDirElementAt(258, x).GetXLink()];
10529  //the above line caused errors when Track->GetTrackElementFromAnyTrackMap in RecoverClipboard had Vector passed in by value,
10530  //causing a bad returned value for SpeedTag and other properties. Passing it in by reference fixed it
10531  TPrefDirElement PDE(TE); //this has Link[4] set
10532  PDE.HLoc = HLoc;
10533  PDE.VLoc = VLoc;
10534  PDE.SetELink(ELink);
10535  PDE.SetXLink(XLink);
10536  bool ELinkPosFound = false, XLinkPosFound = false; //these ensure that the link pos is set as low as possible for points
10537  for(int y = 0; y < 4; y++) //changed to y at v2.9.1
10538  {
10539  if(!ELinkPosFound && (PDE.Link[y] == ELink))
10540  {
10541  PDE.SetELinkPos(y);
10542  ELinkPosFound = true;
10543  }
10544  if(!XLinkPosFound && (PDE.Link[y] == XLink))
10545  {
10546  PDE.SetXLinkPos(y);
10547  XLinkPosFound = true;
10548  }
10549  }
10550  //set the CheckCount as before - added at v2.9.1
10551  PDE.SetCheckCount(9); //explicitly set to 9 at v2.9.2
10554  //set the TrackVectorPosition to correspond to the corresponding TrackElement added at v2.9.1
10555  bool FoundFlag = false;
10556  PDE.SetTrackVectorPosition(Track->GetVectorPositionFromTrackMap(65, OriginalHLoc, OriginalVLoc, FoundFlag)); //uses original TV position as TrackMap hasn't changed yet
10557  if(PDE.GetSignedIntTrackVectorPosition() < 0)
10558  {
10559  FoundFlag = false; //probably will be anyway but reset to be sure & test below
10560  }
10562  if(!PDE.EntryExitNumber() || !ELinkPosFound || !XLinkPosFound || !FoundFlag) //error if can't set the number, any link pos not set or !FoundFlag
10563  {
10565  ShowMessage("Unable to re-orientate the preferred directions, these won't be set in the rotated selection");
10566  break;
10567  }
10568  SelectPrefDir->PrefDirVector.at(x) = PDE;
10569  }
10570  TrainController->LogEvent("RotLeft-PDrotate ok");
10571  // reset values in SelectTextVector
10572  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
10573  {
10574 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
10575 // & if a lot then some will extend beyond the selection
10577  // also subtract half font height for each letter of text, brings position approximately right horizontally
10578  TextItem->HPos = (SelectRect.left) * 16;
10579  TextItem->VPos = (SelectRect.top + x) * 16;
10580  }
10581  TrainController->LogEvent("RotLeft-textrotate ok");
10582  // reset values in SelectGraphicVector
10583  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
10584  {
10585  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
10586  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
10587  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
10588  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
10589  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
10590  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
10591  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
10592  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
10593  }
10594  Screen->Cursor = TCursor(-2); // Arrow
10596  SetLevel2TrackMode(62);
10597  Utilities->CallLogPop(2124);
10598  }
10599  catch(const Exception &e)
10600  {
10601  ErrorLog(206, e.Message);
10602  }
10603 }
10604 
10605 // ---------------------------------------------------------------------------
10606 
10607 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
10608 {
10609  try
10610  {
10611  TrainController->LogEvent("PasteMenuItemClick");
10612  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
10613  // Level1Mode = TrackMode;
10614  // SetLevel1Mode(74);
10616  SetLevel2TrackMode(58);
10617  Utilities->CallLogPop(2060);
10618  }
10619  catch(const Exception &e)
10620  {
10621  ErrorLog(198, e.Message);
10622  }
10623 }
10624 
10625 // ---------------------------------------------------------------------------
10626 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
10627 {
10628  try
10629  {
10630  TrainController->LogEvent("DeleteMenuItemClick");
10631  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
10632  // Level1Mode = TrackMode;
10633  // SetLevel1Mode(75);
10635  SetLevel2TrackMode(38);
10636  Utilities->CallLogPop(1193);
10637  }
10638  catch(const Exception &e)
10639  {
10640  ErrorLog(153, e.Message);
10641  }
10642 }
10643 // ---------------------------------------------------------------------------
10644 
10645 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
10646 {
10647  try
10648  {
10649  TrainController->LogEvent("SelectLengthsMenuItemClick");
10650  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
10651  TrackElementPanel->Visible = false;
10652  TrackLengthPanel->Visible = true;
10653  TrackLengthPanel->SetFocus();
10654  SelectLengthsFlag = true;
10655  InfoPanel->Visible = true;
10656  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
10658  {
10659  ShowMessage("Note: length value will apply to each element's track within the selection.\n\nThis message will not be shown again.");
10660  LengthWarningSentFlag = true;
10661  }
10662  DistanceBox->Text = "";
10663  SpeedLimitBox->Text = "";
10666 // ResetChangedFileDataAndCaption(, true); //don't need this here after 2.7.0 as included in TrackLengthPanel buttons
10667  Utilities->CallLogPop(1414);
10668  }
10669  catch(const Exception &e)
10670  {
10671  ErrorLog(154, e.Message);
10672  }
10673 }
10674 
10675 // ---------------------------------------------------------------------------
10676 
10677 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
10678 {
10679 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
10680  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
10681 */
10682  try
10683  {
10684  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
10685  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
10687  bool FoundFlag = false;
10688  if(Track->SelectVector.empty())
10689  {
10690  Utilities->CallLogPop(1550);
10691  return;
10692  }
10693  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
10694  {
10695  TTrackElement TE = Track->SelectVectorAt(14, x);
10696  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
10697  if(FoundFlag)
10698  {
10699  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
10700  {
10701  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10703  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10705  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
10707  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
10709  }
10710  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
10711  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
10712  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
10713  // at the same position
10714  {
10715  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
10717  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
10719  }
10720  }
10721  }
10723  ResetChangedFileDataAndCaption(22, false);
10724  // RlyFile = false; - don't alter this just for PrefDir changes
10725  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
10726  SetLevel1Mode(30);
10728  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
10729  Utilities->CallLogPop(1549);
10730  }
10731  catch(const Exception &e)
10732  {
10733  ErrorLog(155, e.Message);
10734  }
10735 }
10736 
10737 // ---------------------------------------------------------------------------
10738 
10739 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
10740 {
10741  try
10742  {
10743  TrainController->LogEvent("CancelSelectionClick");
10744  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
10745 // ClearandRebuildRailway(46); //called below
10746  SelectionValid = false;
10747  CancelSelectionFlag = true; // used to avoid RecoverClipboard in pasting when CutMoving selected
10748  Track->CopyFlag = false;
10750  if(Level1Mode == TrackMode)
10751  {
10752  SetLevel1Mode(76); // CancelSelectionFlag needed here
10754  SetLevel2TrackMode(68);
10755  }
10756  else if(Level1Mode == PrefDirMode)
10757  {
10758  SetLevel1Mode(32);
10759  }
10760  CancelSelectionFlag = false; // done with it
10761  ResetSelectRect();
10762  ClearandRebuildRailway(82); // to remove the selection outline
10763  Clipboard()->Clear();
10764  Clipboard()->Close();
10765  Utilities->CallLogPop(1413);
10766  }
10767  catch(const EClipboardException &e) // take no action //non error catch
10768  {
10769 // Application->MessageBox(L"A clipboard error occurred in the cancel function", L"Message", MB_OK);
10770  Utilities->CallLogPop(2314);
10771  }
10772  catch(const Exception &e)
10773  {
10774  ErrorLog(156, e.Message);
10775  }
10776 }
10777 
10778 // ---------------------------------------------------------------------------
10779 
10780 void __fastcall TInterface::CheckPrefDirConflictsMenuItemClick(TObject *Sender)
10781 {
10782 //Conflicts consist of a preferred direction (PD) that links to a track element without a PD on it, or a PD that links to another PD that is set
10783 //in the wrong direction. Points or crossovers with no PD set on one leg are ok as a PD on the other leg doesn't link to it.
10784 
10785  try
10786  {
10787  TrainController->LogEvent("CheckPrefDirConflictsMenuItemClick");
10788  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CheckPrefDirConflictsMenuItemClick");
10789  bool FoundFlag; //not used
10790  int PD0, PD1, PD2, PD3, HLoc, VLoc, LastHLoc = -2000000, LastVLoc = -2000000; //well outside any conceivable range
10791  AnsiString TempInfo = InfoPanel->Caption;
10792  if(EveryPrefDir->PrefDirSize() <= 0)
10793  {
10794  ShowMessage("No preferred directions set.");
10795  Utilities->CallLogPop(2301);
10796  return;
10797  }
10798  else
10799  {
10800  //iterate the map rather than the vector so that pref dirs at the same H & V are consecutive, & can prevent the same element showing more than once
10801  InfoPanel->Visible = true;
10802  InfoPanel->Caption = "Checking preferred directions - please wait";
10803  InfoPanel->Update();
10804  THVPair LastHVPair;
10805  LastHVPair.first = -2000000;
10806  LastHVPair.second = -2000000; //well outside any conceivable range
10807  Screen->Cursor = TCursor(-11); // Hourglass
10808  for(TOnePrefDir::TPrefDir4MultiMapIterator PDMMIt = EveryPrefDir->PrefDir4MultiMap.begin(); PDMMIt != EveryPrefDir->PrefDir4MultiMap.end(); PDMMIt++)
10809  {
10810  bool BiDirLinkFound = true;
10811  int LinkedPrefDirVectorNumber; //not used
10812  THVPair CurrentHVPair = PDMMIt->first;
10813  if(CurrentHVPair != LastHVPair) //dont repeat for remaining elements at same position
10814  {
10815  //For bi-directional pref dirs as long as they link to another pref dir then ok, can't just link to a blank element
10816  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(16, PDMMIt->first.first, PDMMIt->first.second, FoundFlag, PD0, PD1, PD2, PD3);
10817  if((PD0 > -1) && (PD1 > -1))
10818  {
10819  if((EveryPrefDir->PrefDirVector.at(PD0).GetELink() == EveryPrefDir->PrefDirVector.at(PD1).GetXLink()) &&
10820  (EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD1).GetELink()))
10821  {
10822  //PD0 & PD1 are bidirectional pref dirs, ensure pref dirs link at both ends, direction doesn't matter for linked pref dir
10823  if(!EveryPrefDir->FindLinkingPrefDir(0, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos(),
10824  EveryPrefDir->PrefDirVector.at(PD0).GetELink(), LinkedPrefDirVectorNumber))
10825  {
10826  BiDirLinkFound = false;
10827  }
10828  if(!EveryPrefDir->FindLinkingPrefDir(1, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos(),
10829  EveryPrefDir->PrefDirVector.at(PD0).GetXLink(), LinkedPrefDirVectorNumber))
10830  {
10831  BiDirLinkFound = false;
10832  }
10833  }
10834  }
10835  if(BiDirLinkFound && (PD0 > -1) && (PD2 > -1))
10836  {
10837  if((EveryPrefDir->PrefDirVector.at(PD0).GetELink() == EveryPrefDir->PrefDirVector.at(PD2).GetXLink()) &&
10838  (EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD2).GetELink()))
10839  {
10840  if(!EveryPrefDir->FindLinkingPrefDir(2, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos(),
10841  EveryPrefDir->PrefDirVector.at(PD0).GetELink(), LinkedPrefDirVectorNumber))
10842  {
10843  BiDirLinkFound = false;
10844  }
10845  if(!EveryPrefDir->FindLinkingPrefDir(3, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos(),
10846  EveryPrefDir->PrefDirVector.at(PD0).GetXLink(), LinkedPrefDirVectorNumber))
10847  {
10848  BiDirLinkFound = false;
10849  }
10850  }
10851  }
10852  if(BiDirLinkFound && (PD0 > -1) && (PD3 > -1))
10853  {
10854  if((EveryPrefDir->PrefDirVector.at(PD0).GetELink() == EveryPrefDir->PrefDirVector.at(PD3).GetXLink()) &&
10855  (EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == EveryPrefDir->PrefDirVector.at(PD3).GetELink()))
10856  {
10857  if(!EveryPrefDir->FindLinkingPrefDir(4, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos(),
10858  EveryPrefDir->PrefDirVector.at(PD0).GetELink(), LinkedPrefDirVectorNumber))
10859  {
10860  BiDirLinkFound = false;
10861  }
10862  if(!EveryPrefDir->FindLinkingPrefDir(5, PD0, EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos(),
10863  EveryPrefDir->PrefDirVector.at(PD0).GetXLink(), LinkedPrefDirVectorNumber))
10864  {
10865  BiDirLinkFound = false;
10866  }
10867  }
10868  }
10869  if(BiDirLinkFound && (PD1 > -1) && (PD2 > -1))
10870  {
10871  if((EveryPrefDir->PrefDirVector.at(PD1).GetELink() == EveryPrefDir->PrefDirVector.at(PD2).GetXLink()) &&
10872  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD2).GetELink()))
10873  {
10874  if(!EveryPrefDir->FindLinkingPrefDir(6, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos(),
10875  EveryPrefDir->PrefDirVector.at(PD1).GetELink(), LinkedPrefDirVectorNumber))
10876  {
10877  BiDirLinkFound = false;
10878  }
10879  if(!EveryPrefDir->FindLinkingPrefDir(7, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos(),
10880  EveryPrefDir->PrefDirVector.at(PD1).GetXLink(), LinkedPrefDirVectorNumber))
10881  {
10882  BiDirLinkFound = false;
10883  }
10884  }
10885  }
10886  if(BiDirLinkFound && (PD1 > -1) && (PD3 > -1))
10887  {
10888  if((EveryPrefDir->PrefDirVector.at(PD1).GetELink() == EveryPrefDir->PrefDirVector.at(PD3).GetXLink()) &&
10889  (EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == EveryPrefDir->PrefDirVector.at(PD3).GetELink()))
10890  {
10891  if(!EveryPrefDir->FindLinkingPrefDir(8, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos(),
10892  EveryPrefDir->PrefDirVector.at(PD1).GetELink(), LinkedPrefDirVectorNumber))
10893  {
10894  BiDirLinkFound = false;
10895  }
10896  if(!EveryPrefDir->FindLinkingPrefDir(9, PD1, EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos(),
10897  EveryPrefDir->PrefDirVector.at(PD1).GetXLink(), LinkedPrefDirVectorNumber))
10898  {
10899  BiDirLinkFound = false;
10900  }
10901  }
10902  }
10903  if(BiDirLinkFound && (PD2 > -1) && (PD3 > -1))
10904  {
10905  if((EveryPrefDir->PrefDirVector.at(PD2).GetELink() == EveryPrefDir->PrefDirVector.at(PD3).GetXLink()) &&
10906  (EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == EveryPrefDir->PrefDirVector.at(PD3).GetELink()))
10907  {
10908  if(!EveryPrefDir->FindLinkingPrefDir(10, PD2, EveryPrefDir->PrefDirVector.at(PD2).GetELinkPos(),
10909  EveryPrefDir->PrefDirVector.at(PD2).GetELink(), LinkedPrefDirVectorNumber))
10910  {
10911  BiDirLinkFound = false;
10912  }
10913  if(!EveryPrefDir->FindLinkingPrefDir(11, PD2, EveryPrefDir->PrefDirVector.at(PD2).GetXLinkPos(),
10914  EveryPrefDir->PrefDirVector.at(PD2).GetXLink(), LinkedPrefDirVectorNumber))
10915  {
10916  BiDirLinkFound = false;
10917  }
10918  }
10919  }
10920  if(!BiDirLinkFound)
10921  {
10922  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
10923  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
10924  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
10925  {
10926  LastHLoc = HLoc;
10927  LastVLoc = VLoc;
10928  while((Display->DisplayOffsetH - HLoc) > 0)
10929  {
10930  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
10931  }
10932  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
10933  {
10935  }
10936  while((Display->DisplayOffsetV - VLoc) > 0)
10937  {
10938  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
10939  }
10940  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
10941  {
10943  }
10945  Display->InvertElement(1, HLoc * 16, VLoc * 16);
10946  Screen->Cursor = TCursor(-2); // Arrow
10947  int Button = Application->MessageBox(L"Possible mismatch in preferred direction links \n"
10948  "at the position shown - see inverted element (may \n"
10949  "be behind this message). \n\n"
10950  "Click 'OK' to ignore and continue checking or \n"
10951  "'Cancel' to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
10952  ClearandRebuildRailway(84); // to clear inversion
10953  if(Button == IDCANCEL)
10954  {
10955  InfoPanel->Caption = TempInfo;
10956  Utilities->CallLogPop(2302);
10957  return;
10958  }
10959  Screen->Cursor = TCursor(-11); // Hourglass
10960  Display->Update();
10961  }
10962  }
10963  }
10964  LastHVPair = CurrentHVPair;
10965 
10966  bool ELinkFound = false, BiDir = false;
10967  int ELink = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELink();
10968  int ELinkPos = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetELinkPos();
10969  if(EveryPrefDir->BiDirectionalPrefDir(0, PDMMIt)) //bi-directional pref dirs dealt with above so don't check & don't mark as a conflict
10970  {
10971  BiDir = true;
10972  ELinkFound = true;
10973  }
10974  else if((ELink > -1) && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos] > -1))
10975  {
10977  Track->TrackElementAt(1024, EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos]).VLoc, FoundFlag, PD0, PD1, PD2, PD3);
10978  if((EveryPrefDir->PrefDirVector.at(PDMMIt->second).TrackType == GapJump) && (ELinkPos == 0)) //0 is the gap position
10979  {
10980  if(PD0 > -1)
10981  {
10982  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType == GapJump) //the corresponding gap
10983  {
10984  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLinkPos() == 0) // entry link is at the gap end so it corresponds
10985  {
10986  ELinkFound = true;
10987  }
10988  }
10989  }
10990  if(PD1 > -1)
10991  {
10992  if(EveryPrefDir->PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
10993  {
10994  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLinkPos() == 0) // entry link is at the gap end so it corresponds
10995  {
10996  ELinkFound = true;
10997  }
10998  }
10999  }
11000  }
11001  if(PD0 > -1)
11002  {
11003  if(EveryPrefDir->PrefDirVector.at(PD0).GetXLink() == (10 - ELink))
11004  {
11005  ELinkFound = true;
11006  }
11007  }
11008  if(PD1 > -1)
11009  {
11010  if(EveryPrefDir->PrefDirVector.at(PD1).GetXLink() == (10 - ELink))
11011  {
11012  ELinkFound = true;
11013  }
11014  }
11015  if(PD2 > -1)
11016  {
11017  if(EveryPrefDir->PrefDirVector.at(PD2).GetXLink() == (10 - ELink))
11018  {
11019  ELinkFound = true;
11020  }
11021  }
11022  if(PD3 > -1)
11023  {
11024  if(EveryPrefDir->PrefDirVector.at(PD3).GetXLink() == (10 - ELink))
11025  {
11026  ELinkFound = true;
11027  }
11028  }
11029  }
11030  if(!ELinkFound && (BiDir || (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[ELinkPos] > -1)))
11031  {
11032  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11033  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11034  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11035  {
11036  LastHLoc = HLoc;
11037  LastVLoc = VLoc;
11038  while((Display->DisplayOffsetH - HLoc) > 0)
11039  {
11040  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11041  }
11042  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11043  {
11045  }
11046  while((Display->DisplayOffsetV - VLoc) > 0)
11047  {
11048  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11049  }
11050  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11051  {
11053  }
11055  Display->InvertElement(2, HLoc * 16, VLoc * 16);
11056  Screen->Cursor = TCursor(-2); // Arrow
11057  int Button = Application->MessageBox(L"Possible mismatch in preferred direction links \n"
11058  "at the position shown - see inverted element (may \n"
11059  "be behind this message). \n\n"
11060  "Click 'OK' to ignore and continue checking or \n"
11061  "'Cancel' to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11062  ClearandRebuildRailway(86); // to clear inversion
11063  if(Button == IDCANCEL)
11064  {
11065  InfoPanel->Caption = TempInfo;
11066  Utilities->CallLogPop(2303);
11067  return;
11068  }
11069  Screen->Cursor = TCursor(-11); //Hourglass
11070  Display->Update();
11071  }
11072  }
11073 
11074  bool XLinkFound = false;
11075  BiDir = false;
11076  int XLink = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLink();
11077  int XLinkPos = EveryPrefDir->PrefDirVector.at(PDMMIt->second).GetXLinkPos();
11078  if(EveryPrefDir->BiDirectionalPrefDir(1, PDMMIt)) //bi-directional pref dirs dealt with above so don't check & don't mark as a conflict
11079  {
11080  BiDir = true;
11081  XLinkFound = true;
11082  }
11083  else if((XLink > -1) && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos] > -1))
11084  {
11086  Track->TrackElementAt(1026, EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos]).VLoc, FoundFlag, PD0, PD1, PD2, PD3);
11087  if((EveryPrefDir->PrefDirVector.at(PDMMIt->second).TrackType == GapJump) && (XLinkPos == 0)) //0 is the gap position
11088  {
11089  if(PD0 > -1)
11090  {
11091  if(EveryPrefDir->PrefDirVector.at(PD0).TrackType == GapJump) //the corresponding gap
11092  {
11093  if(EveryPrefDir->PrefDirVector.at(PD0).GetELinkPos() == 0) // entry link is at the gap end so it corresponds
11094  {
11095  XLinkFound = true;
11096  }
11097  }
11098  }
11099  if(PD1 > -1)
11100  {
11101  if(EveryPrefDir->PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
11102  {
11103  if(EveryPrefDir->PrefDirVector.at(PD1).GetELinkPos() == 0) // entry link is at the gap end so it corresponds
11104  {
11105  XLinkFound = true;
11106  }
11107  }
11108  }
11109  }
11110  if(PD0 > -1)
11111  {
11112  if(EveryPrefDir->PrefDirVector.at(PD0).GetELink() == (10 - XLink))
11113  {
11114  XLinkFound = true;
11115  }
11116  }
11117  if(PD1 > -1)
11118  {
11119  if(EveryPrefDir->PrefDirVector.at(PD1).GetELink() == (10 - XLink))
11120  {
11121  XLinkFound = true;
11122  }
11123  }
11124  if(PD2 > -1)
11125  {
11126  if(EveryPrefDir->PrefDirVector.at(PD2).GetELink() == (10 - XLink))
11127  {
11128  XLinkFound = true;
11129  }
11130  }
11131  if(PD3 > -1)
11132  {
11133  if(EveryPrefDir->PrefDirVector.at(PD3).GetELink() == (10 - XLink))
11134  {
11135  XLinkFound = true;
11136  }
11137  }
11138  }
11139  if(!XLinkFound && (EveryPrefDir->PrefDirVector.at(PDMMIt->second).Conn[XLinkPos] > -1))
11140  {
11141  HLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).HLoc;
11142  VLoc = EveryPrefDir->PrefDirVector.at(PDMMIt->second).VLoc;
11143  if((LastHLoc != HLoc) || (LastVLoc != VLoc))
11144  {
11145  LastHLoc = HLoc;
11146  LastVLoc = VLoc;
11147  while((Display->DisplayOffsetH - HLoc) > 0)
11148  {
11149  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
11150  }
11151  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
11152  {
11154  }
11155  while((Display->DisplayOffsetV - VLoc) > 0)
11156  {
11157  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
11158  }
11159  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
11160  {
11162  }
11164  Display->InvertElement(3, HLoc * 16, VLoc * 16);
11165  Screen->Cursor = TCursor(-2); // Arrow
11166  int Button = Application->MessageBox(L"Possible mismatch in preferred direction links \n"
11167  "at the position shown - see inverted element (may \n"
11168  "be behind this message). \n\n"
11169  "Click 'OK' to ignore and continue checking or \n"
11170  "'Cancel' to allow correction.", L"Warning", MB_OKCANCEL | MB_ICONWARNING);
11171  ClearandRebuildRailway(88); // to clear inversion
11172  if(Button == IDCANCEL)
11173  {
11174  InfoPanel->Caption = TempInfo;
11175  Utilities->CallLogPop(2304);
11176  return;
11177  }
11178  Screen->Cursor = TCursor(-11); // Hourglass
11179  Display->Update();
11180  }
11181  }
11182  }
11183  }
11184  Screen->Cursor = TCursor(-2); // Arrow
11185  ShowMessage("Finished");
11186  InfoPanel->Caption = TempInfo;
11187  Utilities->CallLogPop(2305);
11188  }
11189  catch(const Exception &e) //non error catch
11190  {
11191  Screen->Cursor = TCursor(-2); // Arrow
11192  ShowMessage("Error in preferred direction checking, unable to complete the check");
11193  Utilities->CallLogPop(2306);
11194  }
11195 }
11196 
11197 //---------------------------------------------------------------------------
11198 
11199 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
11200 {
11201  try
11202  {
11203  TrainController->LogEvent("LoadTimetableMenuItemClick");
11204  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
11205  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
11206  // reset all message flags, stops them being given twice new at v2.4.0
11207  TrainController->SSHigh = false;
11208  TrainController->MRSHigh = false;
11209  TrainController->MRSLow = false;
11210  TrainController->MassHigh = false;
11211  TrainController->BFHigh = false;
11212  TrainController->BFLow = false;
11213  TrainController->PwrHigh = false;
11214  TrainController->SigSHigh = false;
11215  TrainController->SigSLow = false;
11216  if(TimetableDialog->Execute())
11217  {
11218  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName)) // new at v2.6.0 to retain a new directory
11219  {
11220  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
11221  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
11222  }
11223  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
11224  bool CheckLocationsExistInRailwayTrue = true;
11225  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
11226  // true for GiveMessages
11227  {
11228  Screen->Cursor = TCursor(-11); // Hourglass;
11229  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
11230  if(TTBLFile.is_open())
11231  {
11232  bool SessionFileFalse = false;
11233  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
11234  {
11235  SaveTempTimetableFile(0, TimetableDialog->FileName);
11236  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
11237 
11238  }
11239  else
11240  {
11241  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
11242  }
11243  Screen->Cursor = TCursor(-2); // Arrow
11244  } // if(TimetableIntegrityCheck
11245  else
11246  {
11247  ShowMessage("Timetable integrity check failed - unable to load " + TimetableDialog->FileName + ". Please check that the file exists and is spelled correctly.");
11248  }
11249  } // if(TimetableDialog->Execute())
11250 
11251  // else ShowMessage("Load Aborted");
11252  Utilities->CallLogPop(752);
11253  }
11254  catch(const Exception &e)
11255  {
11256  ErrorLog(34, e.Message);
11257  }
11258 }
11259 
11260 // ---------------------------------------------------------------------------
11261 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
11262 {
11263  try
11264  {
11265  TrainController->LogEvent("SignallerControl1Click");
11266  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
11268  Train.SignallerStoppingFlag = false;
11269  Train.TrainMode = Signaller;
11270  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
11271  {
11272  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
11273  }
11274  if(Train.Stopped())
11275  {
11276  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
11277  }
11278  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
11280  Train.PlotTrain(5, Display);
11281  AnsiString LocName = "";
11282  if(Train.LeadElement > -1)
11283  {
11284  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
11285  }
11286  if((LocName == "") && (Train.MidElement > -1))
11287  {
11288  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
11289  }
11290  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
11291  if(Train.StoppedAtLocation && (LocName != ""))
11292  {
11293  Train.RestoreTimetableLocation = LocName;
11294  }
11295  else
11296  {
11297  Train.RestoreTimetableLocation = "";
11298  }
11299  // check whether need to offer 'pass red signal'
11300  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
11301  {
11302  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
11303  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
11304  if((NextElementPosition > -1) && (NextEntryPos > -1))
11305  {
11306  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
11307  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
11308  {
11309  // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
11310  // forwards, but don't change the background colour so still shows as stopped at location
11311  Train.StoppedAtSignal = true;
11312  }
11313  }
11314  }
11315  // find element ID if no locname
11316  if((LocName == "") && Train.LeadElement > -1)
11317  {
11318  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
11319  }
11320  if((LocName == "") && (Train.MidElement > -1))
11321  {
11322  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
11323  }
11324  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11325  Utilities->CallLogPop(1772);
11326  }
11327  catch(const Exception &e)
11328  {
11329  ErrorLog(157, e.Message);
11330  }
11331 }
11332 
11333 // ---------------------------------------------------------------------------
11334 
11335 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
11336 {
11337  try
11338  {
11339  TrainController->LogEvent("TimetableControlMenuItemClick");
11340  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
11342  Train.SignallerStoppingFlag = false;
11343  Train.TrainMode = Timetable;
11344  Train.SignallerStopped = false;
11345  Train.StoppedAfterSPAD = false;
11346  Train.SPADFlag = false;
11349 // red headcode[0]
11350  Train.PlotTrain(6, Display);
11351  AnsiString LocName = "", LeadElementLocName = "", MidElementLocName = "", RequiredLocName = Train.ActionVectorEntryPtr->LocationName;
11352  if(Train.LeadElement > -1) //this naming procedure changed at v2.9.1 as a train might have one element at a station and the other at a non-station named location
11353  //but only one is the location in the timetable, and that is the RequiredLocName. Discovered for LS41 at Lincoln.
11354  {
11355  LeadElementLocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
11356  }
11357  if(Train.MidElement > -1)
11358  {
11359  MidElementLocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
11360  }
11361  if((LeadElementLocName == "") && (MidElementLocName == "") && (Train.LeadElement > -1))
11362  {
11363  LeadElementLocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
11364  }
11365  if((LeadElementLocName == "") && (Train.MidElement > -1))
11366  {
11367  MidElementLocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
11368  }
11369  if((LeadElementLocName == RequiredLocName) || (MidElementLocName == RequiredLocName))
11370  {
11371  LocName = RequiredLocName;
11372  }
11373  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
11374  {
11375  Train.StoppedAtLocation = true;
11376  Train.StoppedAtSignal = false;
11377 // added at v2.7.0 as if had been stopped at signal before tt control restored then background colour would change to normal when signal cleared even when not due to depart
11378  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
11379  // depart the departure time & TRS time have already been calculated so need to
11380  // force a recalculation - see below
11381  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
11382  if(!Train.TrainFailed)
11383  {
11385  } // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11386 
11387  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
11388  {
11389  // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
11390  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
11391  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
11392  }
11393  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
11394  {
11395  // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
11396  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
11397  Train.TimeTimeLocArrived = true;
11398  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
11399  }
11400  }
11401  else
11402  {
11403  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas' error
11404  int NextEntryPos = -1; // ---ditto---
11405  if(Train.LeadElement > -1) // ---ditto---
11406  {
11407  // ---ditto---
11408  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11409  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11410  } // ---ditto---
11411 
11412  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11413  if(!Train.TrainFailed)
11414  {
11415  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
11416  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
11417 
11418  if(Train.AbleToMove(1)) // if has no power
11419  {
11420  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
11421  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
11422  Train.FirstHalfMove = true; // ---Ditto---
11423  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
11424  {
11425  // Train.EntrySpeed = 0;
11426  // Train.EntryTime = TrainController->TTClockTime;
11427  // Train.FirstHalfMove = true;
11428  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
11429  }
11430  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
11431  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
11432  {
11433  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
11434  }
11435  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
11436  {
11437  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
11438  }
11439  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
11440  {
11441  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
11442  }
11443  }
11444  else if(Train.StoppedAtSignal)
11445  {
11446  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11447  if(!Train.TrainFailed)
11448  {
11450  }
11451  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
11452  }
11453  }
11454  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11455  Utilities->CallLogPop(1195);
11456  }
11457  catch(const Exception &e)
11458  {
11459  ErrorLog(158, e.Message);
11460  }
11461 }
11462 
11463 // ---------------------------------------------------------------------------
11464 
11465 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
11466 {
11467  try
11468  {
11469  TrainController->LogEvent("ChangeDirectionMenuItemClick");
11470  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
11472  Train.SignallerStoppingFlag = false;
11473  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
11474  Train.SignallerStopped = true;
11475  AnsiString LocName = "";
11476  if(Train.LeadElement > -1)
11477  {
11478  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
11479  }
11480  if((LocName == "") && (Train.MidElement > -1))
11481  {
11482  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
11483  }
11484  if((LocName == "") && Train.LeadElement > -1)
11485  {
11486  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
11487  }
11488  if((LocName == "") && (Train.MidElement > -1))
11489  {
11490  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
11491  }
11492  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11493  Utilities->CallLogPop(1196);
11494  }
11495  catch(const Exception &e)
11496  {
11497  ErrorLog(159, e.Message);
11498  }
11499 }
11500 // ---------------------------------------------------------------------------
11501 
11502 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
11503 {
11504  try
11505  {
11506  TrainController->LogEvent("MoveForwardsMenuItemClick");
11507  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
11509  Train.SignallerStoppingFlag = false;
11510  if(!Train.AbleToMove(2))
11511  {
11512  // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
11513  Utilities->CallLogPop(1197);
11514  return;
11515  }
11516  Train.SignallerStopped = false;
11517  Train.StoppedAfterSPAD = false; // in case had been set
11518  Train.SPADFlag = false;
11519  Train.StoppedAtLocation = false; // may not have been set but reset anyway
11520  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11522  Train.EntrySpeed = 0;
11524  Train.FirstHalfMove = true;
11525  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
11526  int NextEntryPos = -1; // ---ditto---
11527  if(Train.LeadElement > -1) // ---ditto---
11528  {
11529  // ---ditto---
11530  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11531  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11532  } // ---ditto---
11533 
11534  if((NextElementPos > -1) && (NextEntryPos > -1))
11535  {
11536  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
11537  }
11538  // else follow the continuations
11539  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
11540  {
11541  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
11542  }
11543  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
11544  {
11545  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
11546  }
11547  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
11548  {
11549  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
11550  }
11551  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11552  Utilities->CallLogPop(1198);
11553  }
11554  catch(const Exception &e)
11555  {
11556  ErrorLog(160, e.Message);
11557  }
11558 }
11559 // ---------------------------------------------------------------------------
11560 
11561 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
11562 {
11563  // new at v2.4.0
11564  try
11565  {
11566  TrainController->LogEvent("JoinedByMenuItemClick");
11567  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
11568  TTrain *TrainToBeJoinedBy;
11570  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
11571  {
11572  if(TrainToBeJoinedBy->TrainMode != Signaller)
11573  {
11574  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
11575  Utilities->CallLogPop(2156);
11576  return;
11577  }
11578  // here if there is an adjacent train under signaller control
11579  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
11580  {
11581  ShowMessage("Can't join two trains when both are without power");
11582  Utilities->CallLogPop(2157);
11583  return;
11584  }
11585  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
11586  // set new values for mass etc
11587  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
11588  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
11589  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
11590  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
11591  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
11592  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
11593  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
11594 
11595  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
11596  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
11597  AnsiString LocName = "";
11598  if(ThisTrain.LeadElement > -1)
11599  {
11600  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
11601  }
11602  if((LocName == "") && (ThisTrain.MidElement > -1))
11603  {
11604  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
11605  }
11606  if((LocName == "") && ThisTrain.LeadElement > -1)
11607  {
11608  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
11609  }
11610  if((LocName == "") && (ThisTrain.MidElement > -1))
11611  {
11612  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
11613  }
11614  ThisTrain.StoppedWithoutPower = true;
11615  if(ThisTrain.PowerAtRail >= 1)
11616  {
11617  ThisTrain.StoppedWithoutPower = false;
11618  }
11619  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
11620  if(!ThisTrain.StoppedAtLocation)
11621  {
11622  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11624  }
11625  else
11626  {
11627  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11629  }
11630  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
11631  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
11632  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
11633  ThisTrain.ZeroPowerNoRearSplitMessage = false;
11634  ThisTrain.FailedTrainNoFinishJoinMessage = false;
11635  ThisTrain.ZeroPowerNoJoinedByMessage = false;
11636  ThisTrain.ZeroPowerNoCDTMessage = false;
11637  ThisTrain.ZeroPowerNoNewServiceMessage = false;
11639  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
11641  Utilities->CallLogPop(2158);
11642  }
11643  }
11644  catch(const Exception &e)
11645  {
11646  ErrorLog(207, e.Message);
11647  }
11648 }
11649 // ---------------------------------------------------------------------------
11650 
11651 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
11652 {
11653  // added at v2.4.0
11654  try
11655  {
11656  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
11657  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
11659  Train.TrainFailed = false;
11660  Train.StoppedWithoutPower = false;
11661  Train.SignallerStopped = true;
11662  if(!Train.StoppedAtLocation)
11663  {
11664  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11666  }
11667  else
11668  {
11669  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11671  }
11672  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
11673  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
11674  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
11675  AnsiString LocName = "";
11676  if(Train.LeadElement > -1)
11677  {
11678  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
11679  }
11680  if((LocName == "") && (Train.MidElement > -1))
11681  {
11682  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
11683  }
11684  if((LocName == "") && Train.LeadElement > -1)
11685  {
11686  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
11687  }
11688  if((LocName == "") && (Train.MidElement > -1))
11689  {
11690  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
11691  }
11692  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
11693  Train.ZeroPowerNoFrontSplitMessage = false;
11694  Train.ZeroPowerNoRearSplitMessage = false;
11695  Train.FailedTrainNoFinishJoinMessage = false;
11696  Train.ZeroPowerNoJoinedByMessage = false;
11697  Train.ZeroPowerNoCDTMessage = false;
11698  Train.ZeroPowerNoNewServiceMessage = false;
11700  Train.ZeroPowerNoRepeatShuttleMessage = false;
11702  Utilities->CallLogPop(2159);
11703  }
11704  catch(const Exception &e)
11705  {
11706  ErrorLog(208, e.Message);
11707  }
11708 }
11709 
11710 // ---------------------------------------------------------------------------
11711 
11712 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
11713 {
11714  try
11715  {
11716  TrainController->LogEvent("SignallerControlStopMenuItemClick");
11717  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
11720  if(Train.LeadElement > -1)
11721  {
11722  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
11723  {
11724  Train.SignallerStoppingFlag = true;
11725  Train.SignallerStopBrakeRate = 0;
11726  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11727  }
11728  else
11729  {
11731  }
11732  }
11733  else
11734  {
11736  }
11737  Utilities->CallLogPop(1553);
11738  }
11739  catch(const Exception &e)
11740  {
11741  ErrorLog(161, e.Message);
11742  }
11743 }
11744 
11745 // ---------------------------------------------------------------------------
11746 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
11747 {
11748  try
11749  {
11750  TrainController->LogEvent("PassRedSignalMenuItemClick");
11751  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
11753  Train.SignallerStoppingFlag = false;
11754  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
11755  if(NextElementPos < 0)
11756  {
11757  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
11758  }
11759  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
11760 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
11761  if(!Train.StoppedAtSignal)
11762  {
11763  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
11764  }
11765 */
11766  if(TrackElement.TrackType != SignalPost)
11767  {
11768  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
11769  }
11770  Train.SignallerStopped = false;
11771  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
11772  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
11773  // since no need to alert the user
11774  Train.StoppedAfterSPAD = false; // in case had been set
11775  Train.SPADFlag = false;
11776  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11778  Train.AllowedToPassRedSignal = true;
11779  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11780  Utilities->CallLogPop(1199);
11781  }
11782  catch(const Exception &e)
11783  {
11784  ErrorLog(162, e.Message);
11785  }
11786 }
11787 // ---------------------------------------------------------------------------
11788 
11789 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
11790 {
11791  try
11792  {
11793  TrainController->LogEvent("StepForwardMenuItemClick");
11794  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
11796  Train.SignallerStoppingFlag = false;
11797  Train.SignallerStopped = false;
11798  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
11799  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
11800  // since no need to alert the user
11801  Train.StoppedAfterSPAD = false; // in case had been set
11802  Train.SPADFlag = false;
11803  Train.StepForwardFlag = true;
11804  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
11805  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
11807  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
11808  int NextElementPos = -1;
11809 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
11810  int NextEntryPos = -1; // ---ditto---
11811  if(Train.LeadElement > -1) // ---ditto---
11812  {
11813  // ---ditto---
11814  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
11815  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
11816  } // ---ditto---
11817 
11818  if((NextElementPos > -1) && (NextEntryPos > -1))
11819  {
11820  // call this after StepForwardFlag set
11821  Train.EntrySpeed = 0;
11823  Train.FirstHalfMove = true;
11824  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
11825  }
11826  Utilities->CallLogPop(1800);
11827  }
11828  catch(const Exception &e)
11829  {
11830  ErrorLog(163, e.Message);
11831  }
11832 }
11833 
11834 // ---------------------------------------------------------------------------
11835 
11836 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
11837 {
11838  try
11839  {
11840  TrainController->LogEvent("RemoveTrainMenuItemClick");
11841  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
11843  if((!Train.Derailed) && (!Train.Crashed))
11844  {
11845  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
11847  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
11848  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
11849  TrainController->BaseTime = TDateTime::CurrentDateTime();
11851  if(button == IDNO)
11852  {
11853  Utilities->CallLogPop(1801);
11854  return;
11855  }
11856  }
11857  Train.SignallerStoppingFlag = false;
11858  Train.TrainGone = true; // will be removed by TTrainController::Operate
11859  Train.SignallerRemoved = true;
11860  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
11861  AnsiString LocName = "";
11862  if(Train.LeadElement > -1)
11863  {
11864  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
11865  }
11866  if((LocName == "") && (Train.MidElement > -1))
11867  {
11868  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
11869  }
11870  if((LocName == "") && Train.LeadElement > -1)
11871  {
11872  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
11873  }
11874  if((LocName == "") && (Train.MidElement > -1))
11875  {
11876  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
11877  }
11878  TTrackElement *TrackElementPtr;
11879  int RouteNumber;
11880  TAllRoutes::TRouteType RouteType;
11881  if(Train.LeadElement > -1)
11882  {
11883  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
11884  // remove TrainIDs from track element, added at v2.4.0
11885  if(TrackElementPtr->TrackType == Bridge)
11886  {
11887  if(Train.LeadExitPos > 1)
11888  {
11889  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
11890  }
11891  else
11892  {
11893  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
11894  }
11895  }
11896  else
11897  {
11898  TrackElementPtr->TrainIDOnElement = -1;
11899  }
11900  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
11901  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
11902  {
11903  TrackElementPtr->CallingOnSet = false;
11904  Track->PlotSignal(6, *TrackElementPtr, Display);
11905  }
11906 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
11907 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
11908  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
11909  if(RouteType == TAllRoutes::AutoSigsRoute)
11910  {
11913  }
11914 // end of addition
11915 
11916 // erase a stub route if there is one, added at v2.6.1
11917 // first element of route is immediately in front of the train
11918  if(Train.LeadExitPos >= 0)
11919  {
11920  TTrackElement LeadTrackElement = Track->TrackElementAt(1013, Train.LeadElement);
11921  int FirstRouteElementVecPos = LeadTrackElement.Conn[Train.LeadExitPos];
11922  int FirstRouteLinkPos = LeadTrackElement.ConnLinkPos[Train.LeadExitPos];
11923  RouteType = AllRoutes->GetRouteTypeAndNumber(39, FirstRouteElementVecPos, FirstRouteLinkPos, RouteNumber);
11924  if(RouteType == TAllRoutes::NotAutoSigsRoute) // red or green route, if no route then ignore
11925  {
11926  TOneRoute &OR = AllRoutes->GetModifiableRouteAt(30, RouteNumber);
11927  TTrackElement TE = Track->TrackElementAt(1014, FirstRouteElementVecPos);
11928  if((TE.TrackType != SignalPost) && (TE.TrackType != Continuation))
11929  // all autosigs routes have signalpost or continuation at 0 so they are automatically excluded
11930  {
11931  bool FirstPass = true; //added at v2.8.0
11932  while(OR.PrefDirSize() > 0)
11933  // remove the route up to but not including the next facing signal, in case a route extends to another signal
11934  {
11935  TPrefDirElement PDE = OR.GetFixedPrefDirElementAt(249, 0);
11936 // these will change at each element removal because OR is a reference to the real route
11937  int TVPos2 = PDE.GetTrackVectorPosition();
11938  if(FirstPass && (TVPos2 != FirstRouteElementVecPos)) //route is not directed away from cdt train, could be a call-on for another train (added at v2.8.0)
11939  {
11940  break;
11941  }
11942  TTrackElement TE2 = Track->TrackElementAt(1015, TVPos2);
11943  if(Track->TrackElementAt(1016, PDE.GetTrackVectorPosition()).Config[PDE.GetXLinkPos()] != Signal)
11944  {
11945  AllRoutes->RemoveRouteElement(24, TE2.HLoc, TE2.VLoc, PDE.GetELink());
11946  }
11947  else
11948  {
11949  break;
11950  }
11951  FirstPass = false;
11952  }
11953  AllRoutes->RebuildRailwayFlag = true;
11954  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to replot without stub route
11955  }
11956  }
11957  }
11958 // end of stub route removal addition
11959  }
11960  if(Train.MidElement > -1)
11961  {
11962  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
11963  // remove TrainIDs from track element, added at v2.4.0
11964  if(TrackElementPtr->TrackType == Bridge)
11965  {
11966  if(Train.MidExitPos > 1)
11967  {
11968  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
11969  }
11970  else
11971  {
11972  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
11973  }
11974  }
11975  else
11976  {
11977  TrackElementPtr->TrainIDOnElement = -1;
11978  }
11979  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
11980  {
11981  TrackElementPtr->CallingOnSet = false;
11982  Track->PlotSignal(7, *TrackElementPtr, Display);
11983  }
11984 // [added at v1.3.0 as above]
11986  {
11987  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
11988  if(RouteType == TAllRoutes::AutoSigsRoute)
11989  {
11992  }
11993  }
11994 // end of addition
11995  }
11996  if(Train.LeadElement > -1)
11997  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
11998  {
11999  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
12000  {
12001  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
12002  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
12003  {
12004  TrackElementPtr->CallingOnSet = false;
12005  Track->PlotSignal(8, *TrackElementPtr, Display);
12006  }
12007  }
12008  }
12009  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
12010  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
12011  {
12012  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
12013  } // entries, including Fer if present
12014 
12015  Utilities->CallLogPop(1200);
12016  }
12017  catch(const Exception &e)
12018  {
12019  ErrorLog(164, e.Message);
12020  }
12021 }
12022 
12023 // ---------------------------------------------------------------------------
12024 
12025 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
12026 // to terminate after error message given
12027 {
12028  ErrorMessage->Visible = false;
12029  ErrorMessageStoreImage->Visible = false;
12030  ErrorButton->Visible = false;
12031  Display->GetImage()->Visible = true;
12032  Application->Terminate();
12033 }
12034 
12035 // ---------------------------------------------------------------------------
12036 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
12037 {
12038  try
12039  {
12040  TrainController->LogEvent("PerformancePanelLabelStartDrag");
12041  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
12042  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
12043  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
12044  Utilities->CallLogPop(1202);
12045  }
12046  catch(const Exception &e)
12047  {
12048  ErrorLog(165, e.Message);
12049  }
12050 }
12051 // ---------------------------------------------------------------------------
12052 
12053 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
12054 {
12055  try
12056  {
12057  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
12058 /* Dropped at v2.9.1 as serves no apparent purpose
12059  if(!FileChangedFlag && !(Track->IsTrackFinished()) && (EveryPrefDir->PrefDirSize() > 0))
12060  {
12061  UnicodeString MessageStr =
12062  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
12063  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12064  if(button == IDNO)
12065  {
12066  Action = caNone; // prevents form & application from closing
12067  Utilities->CallLogPop(1712);
12068  return;
12069  }
12070  }
12071 */
12073  {
12074  UnicodeString MessStr = "";
12076  {
12077  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
12078  }
12079  else if(FileChangedFlag)
12080  {
12081  MessStr = UnicodeString("The railway has changed, exit without saving?");
12082  }
12083  else
12084  {
12085  MessStr = UnicodeString("The timetable has changed, exit without saving?");
12086  }
12087  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
12088  if(button == IDNO)
12089  {
12090  Action = caNone; // prevents form & application from closing
12091  Utilities->CallLogPop(1133);
12092  return;
12093  }
12094  }
12095  if(Level1Mode == OperMode)
12096  {
12098  {
12099  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
12100  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
12102  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12103  TrainController->BaseTime = TDateTime::CurrentDateTime();
12105  if(button == IDNO)
12106  {
12107  Action = caNone; // prevents form & application from closing
12108  Utilities->CallLogPop(969);
12109  return;
12110  }
12111  }
12113  Utilities->PerformanceFile.close();
12114  }
12115  if((TempTTFileName != "") && FileExists(TempTTFileName))
12116  {
12117  DeleteFile(TempTTFileName);
12118  }
12119  Utilities->CallLogPop(971);
12120  }
12121  catch(const Exception &e)
12122  {
12123  ErrorLog(166, e.Message);
12124  }
12125 }
12126 
12127 // ---------------------------------------------------------------------------
12128 
12129 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
12130 {
12131 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
12132 // drop event log as have too many spurious entries
12133  try
12134  {
12135  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
12136  {
12137  if(Key == '2')
12138  {
12139  if(CallLogTickerLabel->Visible)
12140  {
12141  CallLogTickerLabel->Visible = false;
12142  }
12143  else
12144  {
12145  CallLogTickerLabel->Visible = true;
12146  }
12147  }
12148  else if(Key == '3')
12149  {
12150  if(DevelopmentPanel->Visible)
12151  {
12152  DevelopmentPanel->Visible = false;
12153  }
12154  else
12155  {
12156  DevelopmentPanel->Visible = true;
12157  DevelopmentPanel->BringToFront();
12158  }
12159  }
12160  else if(Key == '4')
12161  {
12162  TestFunction();
12163  }
12164  else if(Key == '5')
12165  {
12166  TMsgDlgButtons Buttons;
12167  Buttons << mbYes << mbNo;
12168  if(MessageDlg("Do you wish to allow facing signals next to bridges? If so please be aware that routes cannot be truncated to these signals.",
12169  mtWarning, Buttons, 0) == mrYes)
12170  {
12172  }
12173  else
12174  {
12176  }
12177  }
12178  }
12179  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12180  {
12181  CtrlKey = true;
12182  }
12183  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
12184  {
12185  ShiftKey = true;
12186  }
12187 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
12188 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
12189 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
12190 
12191 // at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
12192 // is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
12193 // won't work on first press and that is less likely to be used a second time on either side of the message
12194 
12195  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
12196  {
12197  if(LastNonCtrlOrShiftKeyDown == Key) // same key still down rejected
12198  {
12199  return;
12200  }
12201  else
12202  {
12204  }
12205  }
12206  if(Key == VK_UP)
12207  {
12208  if(ScreenUpButton->Enabled)
12209  {
12210  ScreenUpButton->Click();
12211  }
12212  }
12213  else if(Key == VK_DOWN)
12214  {
12215  if(ScreenDownButton->Enabled)
12216  {
12217  ScreenDownButton->Click();
12218  }
12219  }
12220  else if(Key == VK_LEFT)
12221  {
12222  if(ScreenLeftButton->Enabled)
12223  {
12224  ScreenLeftButton->Click();
12225  }
12226  }
12227  else if(Key == VK_RIGHT)
12228  {
12229  if(ScreenRightButton->Enabled)
12230  {
12231  ScreenRightButton->Click();
12232  }
12233  }
12234  else if(Key == VK_HOME)
12235  {
12236  if(HomeButton->Enabled)
12237  {
12238  HomeButton->Click();
12239  }
12240  }
12241 // end of 1.3.0 addition
12242  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
12243  {
12244  if(ZoomButton->Enabled)
12245  {
12246  ZoomButton->Click();
12247  }
12248  }
12249  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
12250  {
12251  if(ZoomButton->Enabled)
12252  {
12253  ZoomButton->Click();
12254  }
12255  }
12256 // below added for v2.4.2 to add more keyboard shortcuts
12257  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
12258  SpeedEditBox2->Focused() || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() ||
12259  SpeedEditBox->Focused() || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
12260  {
12261  // prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
12262  return;
12263  }
12264  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
12265  {
12266  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h')) // TimetablePanel uses Shift H too so disable this when it's in use
12267  {
12268  NewHomeButton->Click();
12269  }
12270  }
12271 // Operating panel
12272  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12273  {
12274  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
12275  if(!Shift.Contains(ssCtrl))
12276  {
12277  if(OperateButton->Visible && OperateButton->Enabled)
12278  {
12279  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
12280  {
12281  OperateButton->Click();
12282  }
12283  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
12284  {
12285  OperateButton->Click();
12286  }
12287  }
12288  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
12289  {
12290  PresetAutoSigRoutesButton->Click();
12291  }
12292  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
12293  {
12294  PerformanceLogButton->Click();
12295  }
12296  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
12297  {
12298  CallingOnButton->Click();
12299  }
12300  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
12301  {
12302  OperatorActionButton->Click();
12303  }
12304  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
12305  {
12306  RouteCancelButton->Click();
12307  }
12308  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
12309  {
12310  TTClockAdjButton->Click();
12311  }
12312  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') // route buttons - autosigs
12313  {
12314  AutoSigsButton->Click();
12315  }
12316  if(SigPrefConsecButton->Visible && SigPrefConsecButton->Enabled && Key == '2') // route buttons - prefdir
12317  {
12318  SigPrefConsecButton->Click();
12319  }
12320  if(SigPrefNonConsecButton->Visible && SigPrefNonConsecButton->Enabled && Key == '4') // added at v2.7.0 for prefdir & any following signal
12321  {
12322  SigPrefNonConsecButton->Click();
12323  }
12324  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') // route buttons - unrestricted
12325  {
12326  UnrestrictedButton->Click();
12327  }
12328  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
12329  {
12330  ExitOperationButton->Click();
12331  }
12332  }
12333  else // CtrlKey down
12334  {
12335  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
12336  {
12337  SaveMenuItem->ShortCut = 0;
12338 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
12339  if(Key == 'S' || Key == 's') // so this will never execute
12340  {
12341  SaveSessionButton->Click();
12342  }
12343  }
12344  }
12345  }
12346 // Timetable clock adjust panel
12347  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
12348  {
12349  // use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
12350  if(Shift.Contains(ssShift))
12351  {
12352  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
12353  {
12354  TTClockExitButton->Click();
12355  }
12356  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
12357  {
12358  TTClockResetButton->Click();
12359  }
12360  }
12361  }
12362 // Track build panel
12363  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
12364  {
12365  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
12366  {
12367  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) // add/remove track elements
12368  {
12369  AddTrackButton->Click();
12370  }
12371  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) // cycle through signal aspects
12372  {
12373  SigAspectButton->Click();
12374  }
12375  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) // link track
12376  {
12377  TrackOKButton->Click();
12378  }
12379  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) // change font
12380  {
12381  FontButton->Click();
12382  }
12383  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) // name locations
12384  {
12385  LocationNameButton->Click();
12386  }
12387  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) // set distances/speeds
12388  {
12389  SetLengthsButton->Click();
12390  }
12391  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) // add text
12392  {
12393  AddTextButton->Click();
12394  }
12395  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) // toggle grid
12396  {
12397  ScreenGridButton->Click();
12398  }
12399  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) // move text or graphic
12400  {
12401  MoveTextOrGraphicButton->Click();
12402  }
12403  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) // insert image
12404  {
12405  UserGraphicButton->Click();
12406  }
12407  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) // join gaps
12408  {
12409  SetGapsButton->Click();
12410  }
12411  }
12412  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12413  {
12414  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) // save railway in trackbuild mode
12415  {
12416  SaveMenuItem->ShortCut = 0;
12417 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
12418  if(Key == 'S' || Key == 's') // so this will never execute
12419  {
12420  SaveRailwayTBPButton->Click();
12421  }
12422  }
12423  }
12424  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
12425  {
12426  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') // escape key
12427  {
12428  ExitTrackButton->Click();
12429  }
12430  }
12431  }
12432 // PrefDir panel
12433  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
12434  {
12435  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12436  {
12437  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') // escape key
12438  {
12439  ExitPrefDirButton->Click();
12440  }
12441  }
12442  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
12443  {
12444  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
12445  {
12446  SaveMenuItem->ShortCut = 0;
12447 // It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
12448  if(Key == 'S' || Key == 's') // so this will never execute
12449  {
12450  SaveRailwayPDPButton->Click();
12451  }
12452  }
12453  }
12454  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12455  {
12456  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) // add pref dir
12457  {
12458  AddPrefDirButton->Click();
12459  }
12460  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) // delete one pref dir
12461  {
12462  DeleteOnePrefDirButton->Click();
12463  }
12464  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) // delete all pref dirs
12465  {
12466  DeleteAllPrefDirButton->Click();
12467  }
12468  }
12469  }
12470 // Note that save button in BaseMode is handled by Ctrl S from the File menu
12471 
12472 // Timetable panel
12473  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
12474  {
12475  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12476  {
12477  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') // escape key
12478  {
12479  ExitTTModeButton->Click();
12480  }
12481  }
12482  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) // show/hide timetable edit panel
12483  {
12484  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
12485  {
12486  if(!TimetableEditPanel->Visible)
12487  {
12488  if(Key == 'S' || Key == 's')
12489  {
12490  ShowHideTTButton->Click();
12491  }
12492  }
12493  else if(Key == 'H' || Key == 'h')
12494  {
12495  ShowHideTTButton->Click();
12496  }
12497  }
12498  }
12499  }
12500 // Timetable edit panel
12501 // These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
12502 // is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
12503 // showing. See DevHistory.txt for the version at v2.5.0 for details.
12504  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
12505  {
12506  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
12507  {
12509 // store value here before the Windows key press function runs (it runs after any local code)
12510  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
12511  {
12512  PreviousTTEntryKeyFlag = true;
12513  }
12514  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
12515  {
12516  NextTTEntryKeyFlag = true;
12517  }
12518  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
12519  {
12520  MoveTTEntryUpKeyFlag = true;
12521  }
12522  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
12523  {
12524  MoveTTEntryDownKeyFlag = true;
12525  }
12526  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
12527  {
12528  CopyTTEntryKeyFlag = true;
12529  }
12530  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
12531  {
12532  CutTTEntryKeyFlag = true;
12533  }
12534  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
12535  {
12536  PasteTTEntryKeyFlag = true;
12537  }
12538  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
12539  {
12540  DeleteTTEntryKeyFlag = true;
12541  }
12542 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
12543  {
12544  SaveTTEntryKeyFlag = true;
12545  }
12546  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
12547  {
12548  CancelTTActionKeyFlag = true;
12549  }
12550 */
12551  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
12552  {
12553  NewTTEntryKeyFlag = true;
12554  }
12555  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
12556  {
12557  AZOrderKeyFlag = true;
12558  }
12559 /*
12560  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
12561  {
12562  AddMinsKeyFlag = true;
12563  }
12564  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
12565  {
12566  SubMinsKeyFlag = true;
12567  }
12568 */
12569  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
12570  {
12572  }
12573  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
12574  {
12575  ValidateTimetableKeyFlag = true;
12576  }
12577  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
12578  {
12579  SaveTTKeyFlag = true;
12580  }
12581  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
12582  {
12583  SaveTTAsKeyFlag = true;
12584  }
12585  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
12586  {
12587  RestoreTTKeyFlag = true;
12588  }
12589  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
12590  {
12591  ExportTTKeyFlag = true;
12592  }
12593  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
12594  {
12595  ConflictAnalysisKeyFlag = true;
12596  }
12597  }
12598  }
12599 // Information menu
12600  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
12601  {
12602  if(Key == 'I' || Key == 'i') // toggle track info
12603  {
12604  TrackInfoOnOffMenuItem->Click();
12605  }
12606  else if(TrainInfoMenuItem->Enabled)
12607  {
12608  if(Key == 'S' || Key == 's') // toggle train status info
12609  {
12611  }
12612  else if(Key == 'T' || Key == 't') // toggle train timetable info
12613  {
12614  TrainTTInfoOnOffMenuItem->Click();
12615  }
12616  }
12617  }
12618 // end of 2.4.2 addition
12619 
12620  }
12621  catch(const Exception &e)
12622  {
12623  ErrorLog(167, e.Message);
12624  }
12625 }
12626 
12627 // ---------------------------------------------------------------------------
12628 
12629 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12630 {
12631  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
12632  {
12633  LastNonCtrlOrShiftKeyDown = -1; // reset value to no key down
12634  }
12635  CtrlKey = false;
12636  ShiftKey = false;
12637  SaveMenuItem->ShortCut = 16467; // restore Ctrl S for save menu in case set to 0 in FormKeyDown
12638 }
12639 
12640 // ---------------------------------------------------------------------------
12641 
12642 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12643 {
12644  if((Button == mbRight) && Level2OperMode == Operating)
12645  {
12646  OutputLog1->Caption = "";
12647  }
12648 }
12649 
12650 // ---------------------------------------------------------------------------
12651 
12652 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12653 {
12654  if((Button == mbRight) && Level2OperMode == Operating)
12655  {
12656  OutputLog2->Caption = "";
12657  }
12658 }
12659 // ---------------------------------------------------------------------------
12660 
12661 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12662 {
12663  if((Button == mbRight) && Level2OperMode == Operating)
12664  {
12665  OutputLog3->Caption = "";
12666  }
12667 }
12668 
12669 // ---------------------------------------------------------------------------
12670 
12671 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12672 {
12673  if((Button == mbRight) && Level2OperMode == Operating)
12674  {
12675  OutputLog4->Caption = "";
12676  }
12677 }
12678 
12679 // ---------------------------------------------------------------------------
12680 
12681 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12682 {
12683  if((Button == mbRight) && Level2OperMode == Operating)
12684  {
12685  OutputLog5->Caption = "";
12686  }
12687 }
12688 // ---------------------------------------------------------------------------
12689 
12690 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12691 {
12692  if((Button == mbRight) && Level2OperMode == Operating)
12693  {
12694  OutputLog6->Caption = "";
12695  }
12696 }
12697 
12698 // ---------------------------------------------------------------------------
12699 
12700 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12701 {
12702  if((Button == mbRight) && Level2OperMode == Operating)
12703  {
12704  OutputLog7->Caption = "";
12705  }
12706 }
12707 
12708 // ---------------------------------------------------------------------------
12709 
12710 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12711 {
12712  if((Button == mbRight) && Level2OperMode == Operating)
12713  {
12714  OutputLog8->Caption = "";
12715  }
12716 }
12717 
12718 // ---------------------------------------------------------------------------
12719 
12720 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12721 {
12722  if((Button == mbRight) && Level2OperMode == Operating)
12723  {
12724  OutputLog9->Caption = "";
12725  }
12726 }
12727 
12728 // ---------------------------------------------------------------------------
12729 
12730 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
12731 {
12732  if((Button == mbRight) && Level2OperMode == Operating)
12733  {
12734  OutputLog10->Caption = "";
12735  }
12736 }
12737 
12738 // ---------------------------------------------------------------------------
12739 
12740 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
12741 {
12742  try
12743  {
12744  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
12745  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
12746  {
12748  SetLevel2OperMode(3);
12749  MasterClock->Enabled = false;
12750  }
12751  AboutForm->ShowModal();
12752  }
12753  catch(const Exception &e)
12754  {
12755  ErrorLog(168, e.Message);
12756  }
12757 }
12758 
12759 // ---------------------------------------------------------------------------
12760 
12761 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
12762 {
12763  try
12764  {
12765  // Helpfile allocated during construction of Interface
12766  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
12767  }
12768  catch(const Exception &e)
12769  {
12770  ErrorLog(175, e.Message);
12771  }
12772 }
12773 
12774 // ---------------------------------------------------------------------------
12775 
12776 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
12777 {
12778  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
12779  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
12780 }
12781 
12782 // ---------------------------------------------------------------------------
12783 
12784 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
12785 {
12786  try
12787  {
12788  TrainController->LogEvent("BlackBgndMenuItemClick");
12789  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
12790  TColor OldTransparentColour = Utilities->clTransparent;
12791  Utilities->clTransparent = TColor(0);
12792  SelectBitmap->TransparentColor = Utilities->clTransparent;
12795 
12796  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
12797  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
12798  Level1Mode = BaseMode;
12799  SetLevel1Mode(128);
12800  Utilities->CallLogPop(1797);
12801  }
12802  catch(const Exception &e)
12803  {
12804  ErrorLog(170, e.Message);
12805  }
12806 }
12807 
12808 // ---------------------------------------------------------------------------
12809 
12810 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
12811 {
12812  try
12813  {
12814  TrainController->LogEvent("WhiteBgndMenuItemClick");
12815  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
12816  TColor OldTransparentColour = Utilities->clTransparent;
12817  Utilities->clTransparent = TColor(0xFFFFFF);
12818  SelectBitmap->TransparentColor = Utilities->clTransparent;
12821 
12822  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
12823  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
12824  Level1Mode = BaseMode;
12825  SetLevel1Mode(129);
12826  Utilities->CallLogPop(1798);
12827  }
12828  catch(const Exception &e)
12829  {
12830  ErrorLog(171, e.Message);
12831  }
12832 }
12833 
12834 // ---------------------------------------------------------------------------
12835 
12836 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
12837 {
12838  try
12839  {
12840  TrainController->LogEvent("BlueBgndMenuItemClick");
12841  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
12842  TColor OldTransparentColour = Utilities->clTransparent;
12843  Utilities->clTransparent = TColor(0x330000);
12844  SelectBitmap->TransparentColor = Utilities->clTransparent;
12847 
12848  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
12849  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
12850  Level1Mode = BaseMode;
12851  SetLevel1Mode(130);
12852  Utilities->CallLogPop(1799);
12853  }
12854  catch(const Exception &e)
12855  {
12856  ErrorLog(172, e.Message);
12857  }
12858 }
12859 
12860 // ---------------------------------------------------------------------------
12861 
12862 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
12863 {
12864  if(SpeedTopLabel->Caption == "mph")
12865  {
12866  SpeedTopLabel->Caption = "km/h";
12867  SpeedBottomLabel->Caption = "mph";
12868  }
12869  else
12870  {
12871  SpeedTopLabel->Caption = "mph";
12872  SpeedBottomLabel->Caption = "km/h";
12873  }
12874  // swap values to match toggle state
12875  UnicodeString SavedTopValue = SpeedEditBox->Text;
12876  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
12877 
12878  SpeedEditBox->Text = SavedBottomValue;
12879  SpeedVariableLabel->Caption = SavedTopValue;
12880 }
12881 // ---------------------------------------------------------------------------
12882 
12883 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
12884 {
12885  if(SpeedTopLabel2->Caption == "mph")
12886  {
12887  SpeedTopLabel2->Caption = "km/h";
12888  SpeedBottomLabel2->Caption = "mph";
12889  }
12890  else
12891  {
12892  SpeedTopLabel2->Caption = "mph";
12893  SpeedBottomLabel2->Caption = "km/h";
12894  }
12895  // swap values to match toggle state
12896  UnicodeString SavedTopValue = SpeedEditBox2->Text;
12897  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
12898 
12899  SpeedEditBox2->Text = SavedBottomValue;
12900  SpeedVariableLabel2->Caption = SavedTopValue;
12901 }
12902 // ---------------------------------------------------------------------------
12903 
12904 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12905 {
12906  try
12907  {
12908  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
12909  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
12910  bool ErrorFlag = false, TooBigFlag = false;
12911  if(SpeedEditBox->Text.Length() > 0)
12912  {
12913  if(SpeedEditBox->Text.Length() > 5)
12914  {
12915  TooBigFlag = true;
12916  }
12917  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
12918  {
12919  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
12920  {
12921  SpeedVariableLabel->Caption = "Entry error";
12922  ErrorFlag = true;
12923  break;
12924  }
12925  if(TooBigFlag)
12926  {
12927  SpeedVariableLabel->Caption = "Too big";
12928  break;
12929  }
12930  }
12931  if(!ErrorFlag && !TooBigFlag)
12932  {
12933 /*
12934  1 mph = 1.609344 km/h
12935  1 km/h = 0.621371 mph
12936 */
12937  if(SpeedTopLabel->Caption == "mph")
12938  {
12939  // do mph-to-km/h conversion
12940  int MPH = SpeedEditBox->Text.ToInt();
12941  int KPH = (MPH * 1.609344) + 0.5;
12942  SpeedVariableLabel->Caption = UnicodeString(KPH);
12943  }
12944  else
12945  {
12946  // do km/h-to-mph conversion
12947  int KPH = SpeedEditBox->Text.ToInt();
12948  int MPH = (KPH * 0.621371) + 0.5;
12949  SpeedVariableLabel->Caption = UnicodeString(MPH);
12950  }
12951  }
12952  }
12953  else
12954  {
12955  SpeedVariableLabel->Caption = "";
12956  }
12957  Utilities->CallLogPop(1865);
12958  }
12959  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non error catch
12960  {
12961  SpeedVariableLabel->Caption = "Entry error";
12962  Utilities->CallLogPop(2307);
12963  }
12964  catch(const Exception &e)
12965  {
12966  ErrorLog(176, e.Message);
12967  }
12968 }
12969 
12970 // ---------------------------------------------------------------------------
12971 
12972 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
12973 {
12974  if(PowerTopLabel->Caption == "HP")
12975  {
12976  PowerTopLabel->Caption = "kW";
12977  PowerBottomLabel->Caption = "HP";
12978  }
12979  else
12980  {
12981  PowerTopLabel->Caption = "HP";
12982  PowerBottomLabel->Caption = "kW";
12983  }
12984  // swap values to match toggle state
12985  UnicodeString SavedTopValue = PowerEditBox->Text;
12986  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
12987 
12988  PowerEditBox->Text = SavedBottomValue;
12989  PowerVariableLabel->Caption = SavedTopValue;
12990 }
12991 // ---------------------------------------------------------------------------
12992 
12993 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12994 {
12995  try
12996  {
12997  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
12998  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
12999  bool ErrorFlag = false, TooBigFlag = false;
13000  if(PowerEditBox->Text.Length() > 0)
13001  {
13002  if(PowerEditBox->Text.Length() > 8)
13003  {
13004  TooBigFlag = true;
13005  }
13006  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
13007  {
13008  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
13009  {
13010  PowerVariableLabel->Caption = "Entry error";
13011  ErrorFlag = true;
13012  break;
13013  }
13014  if(TooBigFlag)
13015  {
13016  PowerVariableLabel->Caption = "Too big";
13017  break;
13018  }
13019  }
13020  if(!ErrorFlag && !TooBigFlag)
13021  {
13022 /*
13023  1 kW = 1.340482574 HP
13024  1 HP = 0.745699872 kW
13025 */
13026  if(PowerTopLabel->Caption == "HP")
13027  {
13028  // do HP-to-kW conv
13029  int HP = PowerEditBox->Text.ToInt();
13030  int KW = (HP * 0.745699872) + 0.5;
13031  PowerVariableLabel->Caption = UnicodeString(KW);
13032  }
13033  else
13034  {
13035  // do kW-to-HP conv
13036  int KW = PowerEditBox->Text.ToInt();
13037  int HP = (KW * 1.340482574) + 0.5;
13038  PowerVariableLabel->Caption = UnicodeString(HP);
13039  }
13040  }
13041  }
13042  else
13043  {
13044  PowerVariableLabel->Caption = "";
13045  }
13046  Utilities->CallLogPop(1868);
13047  }
13048  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non error catch
13049  {
13050  PowerVariableLabel->Caption = "Entry error";
13051  Utilities->CallLogPop(2308);
13052  }
13053  catch(const Exception &e)
13054  {
13055  ErrorLog(179, e.Message);
13056  }
13057 }
13058 // ---------------------------------------------------------------------------
13059 
13060 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13061 {
13062  try
13063  {
13064  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
13065  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
13066  bool ErrorFlag = false, TooBigFlag = false;
13067  if(SpeedEditBox2->Text.Length() > 0)
13068  {
13069  if(SpeedEditBox2->Text.Length() > 5)
13070  {
13071  TooBigFlag = true;
13072  }
13073  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
13074  {
13075  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
13076  {
13077  SpeedVariableLabel2->Caption = "Entry error";
13078  ErrorFlag = true;
13079  break;
13080  }
13081  if(TooBigFlag)
13082  {
13083  SpeedVariableLabel2->Caption = "Too big";
13084  break;
13085  }
13086  }
13087  if(!ErrorFlag && !TooBigFlag)
13088  {
13089 /*
13090  1 mph = 1.609344 km/h
13091  1 km/h = 0.621371 mph
13092 */
13093  if(SpeedTopLabel2->Caption == "mph")
13094  {
13095  // do mph-to-km/h conversion
13096  int MPH = SpeedEditBox2->Text.ToInt();
13097  int KPH = (MPH * 1.609344) + 0.5;
13098  SpeedVariableLabel2->Caption = AnsiString(KPH);
13099  }
13100  else
13101  {
13102  // do km/h-to-mph conversion
13103  int KPH = SpeedEditBox2->Text.ToInt();
13104  int MPH = (KPH * 0.621371) + 0.5;
13105  SpeedVariableLabel2->Caption = AnsiString(MPH);
13106  }
13107  }
13108  }
13109  else
13110  {
13111  SpeedVariableLabel2->Caption = "";
13112  }
13113  Utilities->CallLogPop(1866);
13114  }
13115  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non error catch
13116  {
13117  SpeedVariableLabel2->Caption = "Entry error";
13118  Utilities->CallLogPop(2309);
13119  }
13120  catch(const Exception &e)
13121  {
13122  ErrorLog(177, e.Message);
13123  }
13124 }
13125 
13126 // ---------------------------------------------------------------------------
13127 
13128 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13129 {
13130  try
13131  {
13132  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
13133  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
13134  bool ErrorFlag = false, TooLongFlag = false;
13135  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
13136  {
13137  for(int x = 1; x <= MileEdit->Text.Length(); x++)
13138  {
13139  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
13140  {
13141  MetreVariableLabel->Caption = "Entry error";
13142  ErrorFlag = true;
13143  break;
13144  }
13145  }
13146  }
13147  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
13148  {
13149  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
13150  {
13151  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
13152  {
13153  MetreVariableLabel->Caption = "Entry error";
13154  ErrorFlag = true;
13155  break;
13156  }
13157  }
13158  }
13159  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
13160  {
13161  for(int x = 1; x <= YardEdit->Text.Length(); x++)
13162  {
13163  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
13164  {
13165  MetreVariableLabel->Caption = "Entry error";
13166  ErrorFlag = true;
13167  break;
13168  }
13169  }
13170  }
13171  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
13172  {
13173  TooLongFlag = true;
13174  MetreVariableLabel->Caption = "Too big";
13175  }
13176  if(!ErrorFlag && !TooLongFlag)
13177  {
13178  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
13179  if(MileEdit->Text.Length() > 0)
13180  {
13181  Miles = MileEdit->Text.ToInt();
13182  }
13183  if(ChainEdit->Text.Length() > 0)
13184  {
13185  Chains = ChainEdit->Text.ToInt();
13186  }
13187  if(YardEdit->Text.Length() > 0)
13188  {
13189  Yards = YardEdit->Text.ToInt();
13190  }
13191  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
13192  MetreVariableLabel->Caption = AnsiString(Metres);
13193  }
13194  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
13195  {
13196  MetreVariableLabel->Caption = "";
13197  }
13198  Utilities->CallLogPop(1867);
13199  }
13200  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash //non error catch
13201  {
13202  MetreVariableLabel->Caption = "Entry error";
13203  Utilities->CallLogPop(2310);
13204  }
13205  catch(const Exception &e)
13206  {
13207  ErrorLog(178, e.Message);
13208  }
13209 }
13210 
13211 // ---------------------------------------------------------------------------
13212 
13213 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
13214 {
13215  try
13216  {
13217  TrainController->LogEvent("TTClockAdjButtonClick");
13218  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
13219 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
13220  Display->HideWarningLog(0); // because this panel overwrites it
13221  TTClockAdjPanel->Visible = true;
13222  TTClockAdjButton->Enabled = false;
13223 /*
13224  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
13225  OperatingPanel->Enabled = false;
13226  ZoomButton->Enabled = false;
13227  HomeButton->Enabled = false;
13228  NewHomeButton->Enabled = false;
13229  ScreenLeftButton->Enabled = false;
13230  ScreenRightButton->Enabled = false;
13231  ScreenUpButton->Enabled = false;
13232  ScreenDownButton->Enabled = false;
13233 */
13234  Utilities->CallLogPop(1875);
13235  }
13236  catch(const Exception &e)
13237  {
13238  ErrorLog(181, e.Message);
13239  }
13240 }
13241 
13242 // ---------------------------------------------------------------------------
13243 
13244 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
13245 {
13246  try
13247  {
13248  TrainController->LogEvent("TTClockExitButtonClick");
13249  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
13250  TTClockAdjPanel->Visible = false;
13251  TTClockAdjButton->Enabled = true;
13252 /* these dealt with in ClockTimer2
13253  ZoomButton->Enabled = true;
13254  HomeButton->Enabled = true;
13255  NewHomeButton->Enabled = true;
13256  ScreenLeftButton->Enabled = true;
13257  ScreenRightButton->Enabled = true;
13258  ScreenUpButton->Enabled = true;
13259  ScreenDownButton->Enabled = true;
13260  OperatingPanel->Enabled = true;
13261  OperatingPanelLabel->Caption = "Operation";
13262 */
13263  Display->ShowWarningLog(0);
13264  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
13265  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
13266  {
13267  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
13269  {
13270  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height) / 2);
13271  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width) / 2);
13272  TTClockAdjustWarningLabel->Caption =
13273  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
13274  TTClockAdjustWarningPanel->Visible = true;
13275  }
13276  }
13277 // Utilities->Clock2Stopped = false; // as above
13279 // to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
13280  Utilities->CallLogPop(1876);
13281  }
13282  catch(const Exception &e)
13283  {
13284  ErrorLog(182, e.Message);
13285  }
13286 }
13287 // ---------------------------------------------------------------------------
13288 
13289 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
13290 {
13291  try
13292  {
13293  TrainController->LogEvent("TTClockx2ButtonClick");
13294  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
13295  TTClockSpeed = 2;
13296  TTClockSpeedLabel->Caption = "x2";
13298  Utilities->CallLogPop(1878);
13299  }
13300  catch(const Exception &e)
13301  {
13302  ErrorLog(184, e.Message);
13303  }
13304 }
13305 
13306 // ---------------------------------------------------------------------------
13307 
13308 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
13309 {
13310  try
13311  {
13312  TrainController->LogEvent("TTClockx4ButtonClick");
13313  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
13314  TTClockSpeed = 4;
13315  TTClockSpeedLabel->Caption = "x4";
13317  Utilities->CallLogPop(1883);
13318  }
13319  catch(const Exception &e)
13320  {
13321  ErrorLog(189, e.Message);
13322  }
13323 }
13324 
13325 // ---------------------------------------------------------------------------
13326 
13327 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
13328 {
13329  try
13330  {
13331  TrainController->LogEvent("TTClockx8ButtonClick");
13332  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
13333  TTClockSpeed = 8;
13334  TTClockSpeedLabel->Caption = "x8";
13336  Utilities->CallLogPop(1884);
13337  }
13338  catch(const Exception &e)
13339  {
13340  ErrorLog(190, e.Message);
13341  }
13342 }
13343 
13344 // ---------------------------------------------------------------------------
13345 
13346 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
13347 {
13348  try
13349  {
13350  TrainController->LogEvent("TTClockx16ButtonClick");
13351  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
13352  TTClockSpeed = 16;
13353  TTClockSpeedLabel->Caption = "x16";
13355  Utilities->CallLogPop(1885);
13356  }
13357  catch(const Exception &e)
13358  {
13359  ErrorLog(191, e.Message);
13360  }
13361 }
13362 
13363 // ---------------------------------------------------------------------------
13364 
13365 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
13366 {
13367  try
13368  {
13369  TrainController->LogEvent("TTClockx1ButtonClick");
13370  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
13371  TTClockSpeed = 1;
13372  TTClockSpeedLabel->Caption = "x1";
13374  Utilities->CallLogPop(1886);
13375  }
13376  catch(const Exception &e)
13377  {
13378  ErrorLog(192, e.Message);
13379  }
13380 }
13381 
13382 // ---------------------------------------------------------------------------
13383 
13384 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
13385 {
13386  try
13387  {
13388  TrainController->LogEvent("TTClockxHalfButtonClick");
13389  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
13390  TTClockSpeed = 0.5;
13391  TTClockSpeedLabel->Caption = "x1/2";
13393  Utilities->CallLogPop(1887);
13394  }
13395  catch(const Exception &e)
13396  {
13397  ErrorLog(193, e.Message);
13398  }
13399 }
13400 
13401 // ---------------------------------------------------------------------------
13402 
13403 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
13404 {
13405  try
13406  {
13407  TrainController->LogEvent("TTClockxQuarterButtonClick");
13408  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
13409  TTClockSpeed = 0.25;
13410  TTClockSpeedLabel->Caption = "x1/4";
13412  Utilities->CallLogPop(1888);
13413  }
13414  catch(const Exception &e)
13415  {
13416  ErrorLog(194, e.Message);
13417  }
13418 }
13419 
13420 // ---------------------------------------------------------------------------
13421 
13422 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
13423 {
13424  // added for v2.3.0 for very big railways
13425  try
13426  {
13427  TrainController->LogEvent("TTClockxEighthButtonClick");
13428  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
13429  TTClockSpeed = 0.125;
13430  TTClockSpeedLabel->Caption = "x1/8";
13432  Utilities->CallLogPop(2099);
13433  }
13434  catch(const Exception &e)
13435  {
13436  ErrorLog(203, e.Message);
13437  }
13438 }
13439 // ---------------------------------------------------------------------------
13440 
13441 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
13442 {
13443  // added for v2.3.0 for very big railways
13444  try
13445  {
13446  TrainController->LogEvent("TTClockxSixteenthButtonClick");
13447  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
13448  TTClockSpeed = 0.0625;
13449  TTClockSpeedLabel->Caption = "x1/16";
13451  Utilities->CallLogPop(2100);
13452  }
13453  catch(const Exception &e)
13454  {
13455  ErrorLog(204, e.Message);
13456  }
13457 }
13458 
13459 // ---------------------------------------------------------------------------
13460 
13461 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
13462 {
13463  try
13464  {
13465  TrainController->LogEvent("TTClockAdd1hButtonClick");
13466  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
13467  double TTClockIncrement = 1.0 / 24;
13468  TrainController->RestartTime += TDateTime(TTClockIncrement);
13471  Utilities->CallLogPop(1879);
13472  }
13473  catch(const Exception &e)
13474  {
13475  ErrorLog(185, e.Message);
13476  }
13477 }
13478 
13479 // ---------------------------------------------------------------------------
13480 
13481 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
13482 {
13483  try
13484  {
13485  TrainController->LogEvent("TTClockAdd10mButtonClick");
13486  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
13487  double TTClockIncrement = 1.0 / 144;
13488  TrainController->RestartTime += TDateTime(TTClockIncrement);
13491  Utilities->CallLogPop(1881);
13492  }
13493  catch(const Exception &e)
13494  {
13495  ErrorLog(187, e.Message);
13496  }
13497 }
13498 
13499 // ---------------------------------------------------------------------------
13500 
13501 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
13502 {
13503  try
13504  {
13505  TrainController->LogEvent("TTClockAdd1mButtonClick");
13506  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
13507  double TTClockIncrement = 1.0 / 1440;
13508  TrainController->RestartTime += TDateTime(TTClockIncrement);
13511  Utilities->CallLogPop(1882);
13512  }
13513  catch(const Exception &e)
13514  {
13515  ErrorLog(188, e.Message);
13516  }
13517 }
13518 
13519 // ---------------------------------------------------------------------------
13520 
13521 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
13522 {
13523  try
13524  {
13525  TrainController->LogEvent("TTClockResetButtonClick");
13526  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
13531  if(TTClockSpeed == 2)
13532  {
13533  TTClockSpeedLabel->Caption = "x2";
13534  }
13535  else if(TTClockSpeed == 4)
13536  {
13537  TTClockSpeedLabel->Caption = "x4";
13538  }
13539  else if(TTClockSpeed == 8)
13540  {
13541  TTClockSpeedLabel->Caption = "x8";
13542  }
13543  else if(TTClockSpeed == 16)
13544  {
13545  TTClockSpeedLabel->Caption = "x16";
13546  }
13547  else if(TTClockSpeed == 0.5)
13548  {
13549  TTClockSpeedLabel->Caption = "x1/2";
13550  }
13551  else if(TTClockSpeed == 0.25)
13552  {
13553  TTClockSpeedLabel->Caption = "x1/4";
13554  }
13555  else if(TTClockSpeed == 0.125)
13556  {
13557  TTClockSpeedLabel->Caption = "x1/8";
13558  }
13559  else if(TTClockSpeed == 0.0625)
13560  {
13561  TTClockSpeedLabel->Caption = "x1/16";
13562  }
13563  else
13564  {
13565  TTClockSpeed = 1;
13566  TTClockSpeedLabel->Caption = "x1";
13567  }
13568  Utilities->CallLogPop(1880);
13569  }
13570  catch(const Exception &e)
13571  {
13572  ErrorLog(186, e.Message);
13573  }
13574 }
13575 
13576 // ---------------------------------------------------------------------------
13577 
13578 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
13579 {
13580  try
13581  {
13582  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
13583  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
13584  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
13585  OperatingPanelLabel->Caption = "Disabled";
13586  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
13587  ZoomButton->Enabled = false;
13588  HomeButton->Enabled = false;
13589  NewHomeButton->Enabled = false;
13590  ScreenLeftButton->Enabled = false;
13591  ScreenRightButton->Enabled = false;
13592  ScreenUpButton->Enabled = false;
13593  ScreenDownButton->Enabled = false;
13594 
13595  Screen->Cursor = TCursor(-11); // Hourglass
13596  TPrefDirElement StartElement, EndElement;
13597  bool PointsChanged, AtLeastOneSet = false;
13598  int LastIteratorValue = 0;
13599  while(true)
13600  {
13601  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
13602  {
13603  break;
13604  }
13605  // rest of routine here - i.e. build the routes
13606  ConstructRoute->ClearRoute(); // in case not empty though should be
13607  AtLeastOneSet = true;
13608  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true)) // true for AutoSigsFlag
13609  {
13610  }
13611  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
13612  PointsChanged))
13613  {
13614  }
13616  }
13617  if(AtLeastOneSet)
13618  {
13621  }
13622  else
13623  {
13624  ShowMessage("No presettable automatic signal routes are available");
13625  }
13626  Screen->Cursor = TCursor(-2); // Arrow
13627  Utilities->CallLogPop(1994);
13628  }
13629  catch(const Exception &e)
13630  {
13631  ErrorLog(195, e.Message);
13632  }
13633 }
13634 
13635 // ---------------------------------------------------------------------------
13636 
13637 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
13638 {
13639  try
13640  {
13641  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
13642  {
13643  // else fails on shutdown because HiddenScreen & other things no longer exist
13644  int DispW = (Interface->Width - 64 - 16) / 16;
13645 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
13646  int DispH = (Interface->Height - 192) / 16;
13647  MainScreen->Width = DispW * 16;
13648  MainScreen->Height = DispH * 16;
13649  Utilities->ScreenElementWidth = DispW;
13650  Utilities->ScreenElementHeight = DispH;
13651  HiddenScreen->Width = MainScreen->Width;
13652  HiddenScreen->Height = MainScreen->Height;
13653  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
13654  PerformancePanel->Left = MainScreen->Left;
13655  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
13656  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
13657  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
13658  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
13659  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
13660  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
13661  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
13662  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
13663  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
13664  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
13665 
13666  if(!Display->ZoomOutFlag)
13667  {
13669  }
13670  else
13671  {
13672  Display->ClearDisplay(11);
13674  }
13675  Display->Update();
13676  }
13677  }
13678  catch(const Exception &e)
13679  {
13680  ErrorLog(197, e.Message);
13681  }
13682 }
13683 
13684 // ---------------------------------------------------------------------------
13685 
13686 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
13687 {
13688  try
13689  {
13690  TrainController->LogEvent("OperatorActionButtonClick");
13691  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
13693  {
13694  ShowOperatorActionPanel = true;
13695  OperatorActionPanel->Visible = true;
13697  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
13698  }
13699  else
13700  {
13701  ShowOperatorActionPanel = false;
13702  OperatorActionPanel->Visible = false;
13704  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
13705  }
13706  Utilities->CallLogPop(2073);
13707  }
13708  catch(const Exception &e)
13709  {
13710  ErrorLog(199, e.Message);
13711  }
13712 }
13713 
13714 // ---------------------------------------------------------------------------
13715 
13717 {
13718  try
13719  {
13720  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
13721  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
13723  if(Utilities->RHSignalFlag) // RH sigs after conversion
13724  {
13725  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
13727  {
13729  }
13730  else
13731  {
13733  }
13734  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
13735  SigsOnLeftImage1->Visible = false;
13736  SigsOnLeftImage2->Visible = false;
13737  SigsOnRightImage1->Visible = true;
13738  SigsOnRightImage2->Visible = true;
13739  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
13740  if(SigFile.fail())
13741  {
13742  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
13743  }
13744  else
13745  {
13746  Utilities->SaveFileString(SigFile, "RHSignals");
13747  }
13748  }
13749  else // LH sigs after conversion
13750  {
13751  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
13753  {
13755  }
13756  else
13757  {
13759  }
13760  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
13761  SigsOnRightImage1->Visible = false;
13762  SigsOnRightImage2->Visible = false;
13763  SigsOnLeftImage1->Visible = true;
13764  SigsOnLeftImage2->Visible = true;
13765  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
13766  if(SigFile.fail())
13767  {
13768  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
13769  }
13770  else
13771  {
13772  Utilities->SaveFileString(SigFile, "LHSignals");
13773  }
13774  }
13775  Utilities->CallLogPop(2097);
13776  }
13777  catch(const Exception &e)
13778  {
13779  ErrorLog(202, e.Message);
13780  }
13781 }
13782 // ---------------------------------------------------------------------------
13783 
13784 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
13785 
13786 {
13787  try
13788  {
13789  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
13790  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
13791  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
13792  {
13793  Utilities->CallLogPop(2160);
13794  return;
13795  }
13796  bool TooBigFlag = false, BadCharsFlag = false;
13799  if(MTBFEditBox->Text.Length() > 0)
13800  {
13801  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
13802  {
13803  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
13804  {
13805  BadCharsFlag = true;
13806  break;
13807  }
13808  }
13809  if(!BadCharsFlag)
13810  {
13811  if(StrToInt(MTBFEditBox->Text) > 10000)
13812  {
13813  TooBigFlag = true;
13814  }
13815  }
13816  if(TooBigFlag)
13817  {
13818  ShowMessage("Maximum value allowed is 10,000");
13819  MTBFEditBox->Text = "";
13822  Utilities->CallLogPop(2161);
13823  return;
13824  }
13825  if(BadCharsFlag)
13826  {
13827  ShowMessage("Value must be a whole number with no special characters");
13828  MTBFEditBox->Text = "";
13831  Utilities->CallLogPop(2162);
13832  return;
13833  }
13834  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
13836  }
13838  {
13839  MTBFEditBox->Text = "";
13841  }
13842  Utilities->CallLogPop(2163);
13843  }
13844  catch(const Exception &e)
13845  {
13846  ErrorLog(209, e.Message);
13847  }
13848 }
13849 
13850 // ---------------------------------------------------------------------------
13851 
13852 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
13853 {
13854  try
13855  {
13856  TrainController->LogEvent("MTBFEditBoxClick");
13857  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
13858  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
13859  {
13860  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
13862  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
13863  }
13864  Utilities->CallLogPop(2164);
13865  }
13866  catch(const Exception &e)
13867  {
13868  ErrorLog(210, e.Message);
13869  }
13870 }
13871 
13872 // ---------------------------------------------------------------------------
13873 
13874 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
13875 {
13876  try
13877  {
13878  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
13879  LengthConversionPanel->Visible = false;
13880  SpeedConversionPanel->Visible = false;
13881  DistanceKey->Visible = false;
13882  TrackElementPanel->Visible = false;
13883  SigAspectButton->Enabled = false;
13885  SetLevel2TrackMode(63);
13886  Display->Update();
13887  if((SelectedGraphicFileName != "") && (!Track->UserGraphicVector.empty()))
13888  // latter condition added at v2.6.0 because showed after ClearAll & reselect failed
13889  {
13890  UserGraphicReselectPanel->Visible = true;
13891  }
13892  else
13893  {
13894  UserGraphicReselectPanel->Visible = false;
13895  LoadUserGraphic(0);
13896  }
13897  Utilities->CallLogPop(2183);
13898  }
13899  catch(const Exception &e)
13900  {
13901  ErrorLog(212, e.Message);
13902  }
13903 }
13904 
13905 // ---------------------------------------------------------------------------
13906 
13907 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
13908 {
13909  try
13910  {
13911  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
13912  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
13913  UserGraphicReselectPanel->Visible = false;
13914  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
13915  if(UGMIt == Track->UserGraphicMap.end())
13916  {
13917  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
13918  Utilities->CallLogPop(2196);
13919  return;
13920  }
13922  SetLevel2TrackMode(64);
13923  Utilities->CallLogPop(2184);
13924  }
13925  catch(const Exception &e)
13926  {
13927  ErrorLog(213, e.Message);
13928  }
13929 }
13930 // ---------------------------------------------------------------------------
13931 
13932 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
13933 {
13934  try
13935  {
13936  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
13937  UserGraphicReselectPanel->Visible = false;
13938  LoadUserGraphic(1);
13939  Utilities->CallLogPop(2185);
13940  }
13941  catch(const Exception &e)
13942  {
13943  ErrorLog(214, e.Message);
13944  }
13945 }
13946 
13947 // ---------------------------------------------------------------------------
13948 
13949 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
13950 {
13951  try
13952  {
13953  TrainController->LogEvent("TTClockAdjustOKButtonClick");
13954  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
13955  TTClockAdjustWarningPanel->Visible = false;
13956  if(TTClockAdjustCheckBox->Checked)
13957  {
13958  TTClockAdjustWarningHide = true;
13959  }
13960  Utilities->CallLogPop(2219);
13961  }
13962  catch(const Exception &e)
13963  {
13964  ErrorLog(216, e.Message);
13965  }
13966 }
13967 
13968 // ---------------------------------------------------------------------------
13969 
13970 void __fastcall TInterface::TwoLocationNameButtonClick(TObject *Sender)
13971 {
13972  try
13973  {
13974  TrainController->LogEvent("TwoLocationNameButtonClick");
13975  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TwoLocationNameButtonClick");
13976  TwoLocationNamePanel->Visible = false;
13977  ShowHideTTButton->Enabled = true;
13978  ExitTTModeButton->Enabled = true;
13979  TimetableEditPanel->Enabled = true;
13980  if(TwoLocationNameCheckBox->Checked)
13981  {
13982  TwoLocationNamePanelHide = true;
13983  }
13984  Utilities->CallLogPop(2316);
13985  }
13986  catch(const Exception &e)
13987  {
13988  ErrorLog(224, e.Message);
13989  }
13990 }
13991 
13992 //---------------------------------------------------------------------------
13993 
13994 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
13995 {
13996  try
13997  {
13998  TrainController->LogEvent("ConflictAnalysisButtonClick");
13999  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
14000  ConflictPanel->Visible = true;
14001  Utilities->CallLogPop(2220);
14002  }
14003  catch(const Exception &e)
14004  {
14005  ErrorLog(217, e.Message);
14006  }
14007 }
14008 
14009 // ---------------------------------------------------------------------------
14010 
14011 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
14012 {
14013  try
14014  {
14015  TrainController->LogEvent("CPCancelButtonClick");
14016  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
14017  ConflictPanel->Visible = false;
14018  Utilities->CallLogPop(2221);
14019  }
14020  catch(const Exception &e)
14021  {
14022  ErrorLog(218, e.Message);
14023  }
14024 }
14025 
14026 // ---------------------------------------------------------------------------
14027 
14028 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
14029 {
14030  try
14031  {
14032  TrainController->LogEvent("CPGenFileButtonClick");
14033  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
14034  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked)
14035  {
14036  ShowMessage("No boxes ticked!");
14037  }
14038  else // keep ticks & range values from last time, only reset on startup
14039  {
14040  Screen->Cursor = TCursor(-11); // hourglass
14041  AnsiString TTTitle;
14043  {
14044  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
14045  {
14046  if(CreateEditTTFileName[x] == '\\')
14047  {
14048  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
14049  break;
14050  }
14051  }
14053  CPAtLocCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
14054  {
14055  ShowMessage("Analysis complete and file created");
14056  }
14057  ConflictPanel->Visible = false;
14058  }
14059  }
14060  Screen->Cursor = TCursor(-2); // arrow
14061  Utilities->CallLogPop(2222);
14062  }
14063  catch(const Exception &e)
14064  {
14065  ErrorLog(219, e.Message);
14066  }
14067 }
14068 
14069 // ---------------------------------------------------------------------------
14070 // end of fastcalls & directly associated functions
14071 // ---------------------------------------------------------------------------
14072 
14073 void TInterface::SetTopIndex(int Caller)
14074 {
14075 // Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
14076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
14077  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
14078  {
14080  }
14081  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
14082  {
14083  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
14084  }
14085  else
14086  {
14087  AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex;
14088  }
14089  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
14090  Utilities->CallLogPop(2207);
14091 }
14092 
14093 // ---------------------------------------------------------------------------
14094 
14095 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
14096 {
14097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
14098  bool ClockState = Utilities->Clock2Stopped;
14099 
14100  Utilities->Clock2Stopped = true;
14102  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
14103  if(ScreenGridFlag && (Level1Mode == TrackMode))
14104  {
14105  int WidthNum = int(MainScreen->Width / 160) + 1;
14106  int HeightNum = int(MainScreen->Height / 144) + 1;
14107  for(int x = 0; x < WidthNum; x++)
14108  {
14109  for(int y = 0; y < HeightNum; y++)
14110  {
14111  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
14112  }
14113  }
14114  }
14115 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
14116 // elements but before active elements. This is so text can overwite stations and non-station named locations.
14117 
14119 
14120 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
14121 // used to occur frequently without Disp->Update() in PlotOriginal
14122 
14123  // OperMode LCs plotted below
14125  {
14127  }
14128  if(Level1Mode == PrefDirMode)
14129  {
14130  if(EveryPrefDir->PrefDirSize() > 0)
14131  {
14133  }
14135  {
14137  }
14138  }
14139  if(Level1Mode == TrackMode)
14140  {
14142  {
14143  LocationNameButton->Enabled = true;
14144  }
14145  else
14146  {
14147  LocationNameButton->Enabled = false;
14148  }
14149  }
14151  {
14153  DistanceKey->Visible = true;
14154  DistancesMarked = true;
14155  LengthConversionPanel->Visible = true;
14156  SpeedConversionPanel->Visible = true;
14157  }
14158  if(Level2TrackMode == DistanceContinuing) // for extended distances
14159  {
14160  if(ConstructPrefDir->PrefDirSize() > 0)
14161  {
14163 // this line was after the next line until v2.5.1, changed so magenta not overrridden after PrefDirMarker called
14165  DistanceKey->Visible = true;
14166  DistancesMarked = true;
14167  LengthConversionPanel->Visible = true;
14168  SpeedConversionPanel->Visible = true;
14169  }
14170  }
14172  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
14173  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
14174  {
14176  DistanceKey->Visible = true;
14177  }
14179  // cancel DistancesMarked if exit from any of these modes
14180  {
14181  DistancesMarked = false;
14182  DistanceKey->Visible = false;
14183  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
14184  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
14185  }
14187  // in process of moving so use NewSelectBitmapHLoc & VLoc
14188  {
14190  }
14191 
14193  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
14194  {
14196  }
14197  if(Level1Mode == OperMode)
14198  {
14200  if(!AllRoutes->LockedRouteVector.empty())
14201  {
14202  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
14203  {
14204  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
14205  {
14206  AllRoutes->LockedRouteVector.erase(LRVIT);
14207  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
14208  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
14209  // route being on the other track of a 2-track element doesn't arise)
14210  continue;
14211  }
14212  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
14213  int x = Route.PrefDirSize() - 1;
14214  bool BreakFlag = false;
14215  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
14216  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
14217  {
14218  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
14219  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
14220  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
14221  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
14222  {
14223  BreakFlag = true;
14224  break; // train removed earlier element from route so stop here
14225  }
14226  x--;
14227  if(x < 0) // added after Albie Vowles reported error on 14/08/20 by email
14228  {
14229  // it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
14230  BreakFlag = true;
14231 // at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
14232  break; // it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
14233  }
14234  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
14235  }
14236  if(!BreakFlag)
14237  {
14238  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
14239  {
14240  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
14241  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
14242  }
14243  }
14244  }
14245  }
14246  if(RouteMode == RouteContinuing)
14247  {
14249 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
14252  if(AutoSigsFlag)
14253  {
14255  }
14256  else if(PreferredRoute) // added at v2.7.0, was ConsecSignalsRoute
14257  {
14259  }
14260  else
14261  {
14263  }
14264  }
14265  if(Track->PointFlashFlag)
14266  {
14267  // need to reset the screen location for picking up the original graphic
14268  int Left, Top; // Embarcadero change - these missing in error from Borland file
14270  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
14271  PointFlash->SetSourceRect(Left, Top);
14272  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
14273  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
14274  }
14275  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
14276  // In order to avoid plotting the whole LC for every element of a LC a bool value - LCPlotted - is used to save time
14277  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
14278  {
14279  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->LCPlotted = false;
14280  }
14281  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
14282  {
14283  int BaseSpeedTag;
14284  TTrackElement ATE;
14285  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
14286  {
14287  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
14288  if(ITE.LCPlotted == false)
14289  {
14290  if(ITE.Attribute == 0)
14291  {
14293  }
14294  else if(ITE.Attribute == 1)
14295  {
14296  // need to determine if should plot green (manual) or red (auto), but all linked LCs have ConsecSignals set to 2 in BarriersDownVector if manual
14297  // so just need to test this for the HLoc & VLoc position match
14298  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
14299  {
14300  if((Track->BarriersDownVector.at(x).HLoc == ITE.HLoc) && (Track->BarriersDownVector.at(x).VLoc == ITE.VLoc))
14301  {
14302  if(Track->BarriersDownVector.at(x).TypeOfRoute == 2)
14303  {
14305  true); // true for manual = green
14306  }
14307  else
14308  {
14310  false); // false for auto = red
14311  }
14312  }
14313  }
14314  }
14315  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting,
14316  // it won't set LCPlotted but no real time lost in this case
14317  }
14318  }
14319  }
14321  }
14322  Display->ZoomOutFlag = false;
14323  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
14324  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
14325  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
14326  Utilities->Clock2Stopped = ClockState;
14327  Utilities->CallLogPop(91);
14328 }
14329 
14330 // ---------------------------------------------------------------------------
14331 
14332 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
14333 {
14334  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
14335  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
14336  {
14337  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
14338  {
14339  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
14340  {
14341  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
14342  }
14344  {
14346  }
14347  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
14348  {
14349  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
14350  }
14352  {
14354  }
14355  }
14356  InfoPanel->Visible = true;
14357  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
14358  ClearandRebuildRailway(31); // get rid of earlier gap selection
14359  Utilities->CallLogPop(92);
14360  return(true); // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
14361  }
14362  Utilities->CallLogPop(93);
14363  return(false); // no unset ones left to find
14364 }
14365 
14366 // ---------------------------------------------------------------------------
14367 
14369 {
14370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
14371  if(FileChangedFlag)
14372  {
14373  UnicodeString MessageStr = "The railway has changed, close it without saving?";
14374  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
14375  if(button == IDNO)
14376  {
14377  Utilities->CallLogPop(1140);
14378  return(false);
14379  }
14380  }
14381  Display->ClearDisplay(7);
14383 
14384  Display->DisplayOffsetH = 0;
14385  Display->DisplayOffsetV = 0;
14390 
14391 // these ensure that all persistent vectors, maps & multimaps etc are cleared
14392  delete TrainController;
14393  delete EveryPrefDir;
14394  delete SelectPrefDir;
14395  delete ConstructRoute;
14396  delete ConstructPrefDir;
14397  delete AllRoutes;
14398  delete Track;
14399  delete TextHandler;
14400 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
14401 // pop earlier pushed values
14402 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
14403 // railway
14404  TextHandler = new TTextHandler;
14405  Track = new TTrack;
14406  AllRoutes = new TAllRoutes;
14408  ConstructRoute = new TOneRoute;
14409  EveryPrefDir = new TOnePrefDir;
14410  SelectPrefDir = new TOnePrefDir;
14412  PerformanceLogBox->Lines->Clear();
14413  ResetAll(1);
14414  Utilities->CallLogPop(94);
14415  return(true);
14416 }
14417 
14418 // ---------------------------------------------------------------------------
14419 
14420 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
14421 {
14422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
14423  std::ifstream VecFile(FileName);
14424 
14425  if(VecFile.is_open())
14426  {
14427  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
14428  {
14429  VecFile.close();
14430  Utilities->CallLogPop(1805);
14431  return(false);
14432  }
14433  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
14434  {
14435  VecFile.close();
14436  Utilities->CallLogPop(1440);
14437  return(false);
14438  }
14439  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
14440  {
14441  VecFile.close();
14442  Utilities->CallLogPop(1441);
14443  return(false);
14444  }
14445  bool GraphicsFollow = false;
14446  int NumberOfActiveElements;
14447  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
14448  {
14449  VecFile.close();
14450  Utilities->CallLogPop(95);
14451  return(false);
14452  }
14453  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
14454  {
14455  VecFile.close();
14456  Utilities->CallLogPop(96);
14457  return(false);
14458  }
14459  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
14460  {
14461  VecFile.close();
14462  Utilities->CallLogPop(97);
14463  return(false);
14464  }
14465  if(GraphicsFollow)
14466  {
14467  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
14468  {
14469  VecFile.close();
14470  Utilities->CallLogPop(2186);
14471  return(false);
14472  }
14473  }
14474  VecFile.close();
14475  }
14476  else
14477  {
14478  Utilities->CallLogPop(1153);
14479  return(false);
14480  }
14481  Utilities->CallLogPop(98);
14482  return(true);
14483 }
14484 
14485 // ---------------------------------------------------------------------------
14486 
14487 void TInterface::Delay(int Caller, double Msec)
14488 {
14489  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
14490  TDateTime First, Second;
14491  bool Finished = false;
14492 
14493  First = TDateTime::CurrentDateTime();
14494  double TimeVal1 = 86400000 * double(First); // no of msec in a day
14495 
14496  while(!Finished)
14497  {
14498  Second = TDateTime::CurrentDateTime();
14499  double TimeVal2 = 86400000 * double(Second);
14500  if((TimeVal2 - TimeVal1) > Msec)
14501  {
14502  Finished = true;
14503  }
14504  }
14505  Utilities->CallLogPop(1203);
14506 }
14507 
14508 // ---------------------------------------------------------------------------
14509 
14511 {
14512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
14513  if(CurrentSpeedButton)
14514  {
14515  CurrentSpeedButton->Down = false;
14516  }
14517  CurrentSpeedButton = 0;
14518  Utilities->CallLogPop(1204);
14519 }
14520 
14521 // ---------------------------------------------------------------------------
14522 
14524 {
14525  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
14526  int TrainID;
14527 
14528  if(ConstructRoute->SearchVectorSize() == 0)
14529  {
14530  Utilities->CallLogPop(99);
14531  return(false);
14532  }
14533  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
14534  {
14535  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
14536  if(PrefDirElement.TrackType == Bridge)
14537  {
14538  if(PrefDirElement.GetXLinkPos() < 2)
14539  {
14540  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
14541  }
14542  else
14543  {
14544  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
14545  }
14546  }
14547  else
14548  {
14549  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
14550  }
14551  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
14552  {
14553  Utilities->CallLogPop(100);
14554  return(true);
14555  }
14556  // check for crossed diagonal fouling by train added at v1.2.0
14557  int TrainID; // not used
14558  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
14559  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
14560  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
14561  {
14562  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
14563  {
14564  Utilities->CallLogPop(2037);
14565  return(true);
14566  }
14567  }
14568  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
14569  {
14570  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
14571  {
14572  Utilities->CallLogPop(2038);
14573  return(true);
14574  }
14575  }
14576  }
14577  Utilities->CallLogPop(101);
14578  return(false);
14579 }
14580 
14581 // ---------------------------------------------------------------------------
14582 
14584 {
14585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
14586  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
14587  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
14588  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
14589  RouteCancelFlag = false;
14591  {
14592  RouteCancelButton->Enabled = true;
14593  }
14594  else
14595  {
14596  RouteCancelButton->Enabled = false;
14597  }
14600 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
14601  InfoPanel->Visible = true;
14602  if(Level2OperMode != Paused)
14603  {
14604  InfoPanel->Caption = InfoCaptionStore;
14605  }
14606  Utilities->CallLogPop(102);
14607 }
14608 
14609 // ---------------------------------------------------------------------------
14610 
14611 // usermode functions below
14613 {
14614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
14615  if(!Display->ZoomOutFlag)
14616  {
14619  Track->GapFlashFlag = false;
14620  }
14621 // GapFlash resets when any mode selected unless zoomed out
14622 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
14623 // reset GapFlashFlag
14624  switch(Level1Mode) // use the data member
14625  {
14626  case BaseMode:
14627  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
14628  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
14629  PasteMenuItem->ShortCut = TextToShortCut("");
14634  LengthConversionPanel->Visible = false;
14635  SpeedConversionPanel->Visible = false;
14636  TimetableEditPanel->Visible = false;
14637  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
14638  TrackBuildPanel->Visible = false;
14639  TrackElementPanel->Visible = false;
14640  LocationNameTextBox->Visible = false;
14641  TextBox->Visible = false;
14642  TrackLengthPanel->Visible = false;
14643  InfoPanel->Visible = false;
14644  PrefDirPanel->Visible = false;
14645  TimetablePanel->Visible = false;
14646  OperatingPanel->Visible = false;
14647  PrefDirKey->Visible = false;
14648  TrackLinkedImage->Visible = false;
14649  TrackNotLinkedImage->Visible = false;
14650  GapsSetImage->Visible = false;
14651  GapsNotSetImage->Visible = false;
14652  LocationNamesSetImage->Visible = false;
14653  LocationNamesNotSetImage->Visible = false;
14654  ModeMenu->Enabled = true;
14655  FileMenu->Enabled = true;
14656  EditMenu->Enabled = false;
14657  BuildTrackMenuItem->Enabled = true;
14658  SigAspectButton->Enabled = false;
14659  Track->ChangingLCVector.clear();
14660  Track->BarriersDownVector.clear();
14662  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
14663  SigImagePanel->Visible = false; // new at v2.3.0
14664  MTBFEditBox->Visible = false; // new at v2.4.0
14665  MTBFLabel->Visible = false;
14666  TTClockAdjustWarningPanel->Visible = false;
14667  if(Track->IsTrackFinished())
14668  {
14669  PlanPrefDirsMenuItem->Enabled = true;
14670  if(TimetableTitle != "")
14671  {
14672  OperateRailwayMenuItem->Enabled = true;
14673  }
14674  else
14675  {
14676  OperateRailwayMenuItem->Enabled = false;
14677  }
14678  }
14679  else
14680  {
14681  PlanPrefDirsMenuItem->Enabled = false;
14682  OperateRailwayMenuItem->Enabled = false;
14683  }
14684  if(RlyFile)
14685  {
14686  LoadTimetableMenuItem->Enabled = true;
14687  }
14688  else
14689  {
14690  LoadTimetableMenuItem->Enabled = false;
14691  }
14692  LoadRailwayMenuItem->Enabled = true;
14693  if(NoRailway())
14694  {
14695  SaveAsMenuItem->Enabled = false;
14696  ImageMenu->Enabled = false;
14697  SaveImageAndGridMenuItem->Enabled = false;
14698  SaveImageNoGridMenuItem->Enabled = false;
14699  SaveImageAndPrefDirsMenuItem->Enabled = false;
14700  SaveOperatingImageMenuItem->Enabled = false;
14701  BlackBgndMenuItem->Enabled = false;
14702  WhiteBgndMenuItem->Enabled = false;
14703  BlueBgndMenuItem->Enabled = false;
14704  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
14705  SigImagePanel->Visible = true; // new at v2.3.0
14706  if(Utilities->clTransparent != TColor(0))
14707  {
14708  BlackBgndMenuItem->Enabled = true;
14709  }
14710  if(Utilities->clTransparent != TColor(0xFFFFFF))
14711  {
14712  WhiteBgndMenuItem->Enabled = true;
14713  }
14714  if(Utilities->clTransparent != TColor(0x330000))
14715  {
14716  BlueBgndMenuItem->Enabled = true;
14717  }
14718  ClearAllMenuItem->Enabled = false;
14719  InfoPanel->Visible = true;
14720  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
14721  }
14722  else
14723  {
14724  InfoPanel->Visible = false;
14725  SaveAsMenuItem->Enabled = true;
14726  ImageMenu->Enabled = true;
14727  SaveImageAndGridMenuItem->Enabled = true;
14728  SaveImageNoGridMenuItem->Enabled = true;
14729  if(EveryPrefDir->PrefDirSize() > 0)
14730  {
14731  SaveImageAndPrefDirsMenuItem->Enabled = true;
14732  }
14733  else
14734  {
14735  SaveImageAndPrefDirsMenuItem->Enabled = false;
14736  }
14737  BlackBgndMenuItem->Enabled = false;
14738  WhiteBgndMenuItem->Enabled = false;
14739  BlueBgndMenuItem->Enabled = false;
14740  SaveOperatingImageMenuItem->Enabled = false;
14741  ClearAllMenuItem->Enabled = true;
14742  }
14743  if(SavedFileName == "")
14744  {
14745  SaveMenuItem->Enabled = false;
14746  }
14747  else if(!FileChangedFlag)
14748  {
14749  SaveMenuItem->Enabled = false;
14750  }
14751  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
14752  {
14753  if(!(Track->IsReadyForOperation(false)))
14754  {
14755  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
14756  }
14757  else
14758  {
14759  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
14760  }
14761  }
14762  else
14763  {
14764  SaveMenuItem->Enabled = true;
14765  }
14766  LoadSessionMenuItem->Enabled = true;
14767  ExitMenuItem->Enabled = true;
14768  ScreenGridFlag = false;
14769  TrainController->CrashWarning = false;
14770  TrainController->DerailWarning = false;
14771  TrainController->SPADWarning = false;
14773  TrainController->CallOnWarning = false;
14776  UserGraphicReselectPanel->Visible = false;
14777  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
14778  SetTrackBuildImages(13);
14779  ClipboardChecked = false;
14780  break;
14781 
14782  case TimetableMode:
14783  if(TwoLocationNamePanel->Visible) //added at v2.9.1 so panel persists until button clicked
14784  {
14785  break;
14786  }
14790  ModeMenu->Enabled = false;
14791  SigImagePanel->Visible = false; // new at v2.3.0
14792  FileMenu->Enabled = false;
14793  EditMenu->Enabled = false;
14794  FloatingInfoMenu->Enabled = false;
14795  ImageMenu->Enabled = false;
14796  TimetableEditPanel->BringToFront();
14797  TimetableHandler();
14798  break;
14799 
14800  case TrackMode:
14801  {
14802  if(Level2TrackMode == CutMoving)
14803  {
14804  Level2TrackMode = Pasting; // paste the selection
14805  SetLevel2TrackMode(52); // CancelSelectionFlag used in Case Pasting
14806  }
14811  TrackBuildPanel->Visible = true;
14812  TrackBuildPanelLabel->Caption = "Build/modify";
14813  TrackElementPanel->Visible = false;
14814  TrackLengthPanel->Visible = false;
14815  PrefDirPanel->Visible = false;
14816  TimetablePanel->Visible = false;
14817  OperatingPanel->Visible = false;
14818  InfoPanel->Visible = false;
14819  InfoPanel->Caption = "";
14820  LocationNameTextBox->Visible = false;
14821  TextBox->Visible = false;
14822  ModeMenu->Enabled = false;
14823  SigImagePanel->Visible = false; // new at v2.3.0
14824  FileMenu->Enabled = false;
14825  // set edit menu items
14827  // display track buttons
14828  AddTrackButton->Enabled = true;
14830  {
14831  LocationNameButton->Enabled = true;
14832  }
14833  else
14834  {
14835  LocationNameButton->Enabled = false;
14836  }
14837  ScreenGridButton->Enabled = true;
14838  ExitTrackButton->Enabled = true;
14839  SetGapsButton->Enabled = false;
14840  TrackOKButton->Enabled = false;
14841  if(Track->GapsUnset(5))
14842  {
14843  SetGapsButton->Enabled = true;
14844  }
14845  // only enable if there are gaps still to be set (returns false for no track)
14846  else
14847  {
14848  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
14849  {
14850  TrackOKButton->Enabled = true;
14851  }
14852  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
14853  }
14854  SetLengthsButton->Enabled = false;
14855  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
14856  {
14857  SetLengthsButton->Enabled = true;
14858  }
14859  // text buttons
14860  AddTextButton->Enabled = true;
14861  TextOrUserGraphicGridButton->Enabled = true;
14862  FontButton->Enabled = true;
14863  MoveTextOrGraphicButton->Enabled = false;
14864  if(TextHandler->TextVectorSize(9) > 0)
14865  {
14866  MoveTextOrGraphicButton->Enabled = true;
14867  }
14868  if(!Track->UserGraphicVector.empty())
14869  {
14870  MoveTextOrGraphicButton->Enabled = true;
14871  }
14872  SelectionValid = false;
14874  TimetableTitle = "";
14875  SetCaption(0);
14876  } break;
14877 
14878  case PrefDirMode:
14879  Screen->Cursor = TCursor(-11); //Hourglass in case many pref dirs
14883  PrefDirPanel->Visible = true;
14884  PrefDirPanelLabel->Caption = "Preferred direction selection";
14885 
14886  InfoPanel->Visible = true;
14887  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
14888  PrefDirKey->Visible = true;
14889  ModeMenu->Enabled = false;
14890  SigImagePanel->Visible = false; // new at v2.3.0
14891  FileMenu->Enabled = false;
14892 // set edit menu items
14894  AddPrefDirButton->Enabled = false;
14895  DeleteOnePrefDirButton->Enabled = false;
14897  if(EveryPrefDir->PrefDirSize() > 0)
14898  {
14899  DeleteAllPrefDirButton->Visible = true;
14900  DeleteAllPrefDirButton->Enabled = true;
14901  SaveImageAndPrefDirsMenuItem->Enabled = true;
14902  }
14903  else
14904  {
14905  DeleteAllPrefDirButton->Enabled = false;
14906  SaveImageAndPrefDirsMenuItem->Enabled = false;
14907  }
14908  ExitPrefDirButton->Enabled = true;
14909  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
14910 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
14911 // SetCaption();
14912  Screen->Cursor = TCursor(-2); //Arrow
14913  break;
14914 
14915  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
14919  OperatingPanel->Visible = true;
14920  OperatingPanelLabel->Caption = "Operation";
14921 
14922  CallingOnButton->Visible = false;
14923  PresetAutoSigRoutesButton->Visible = true;
14924  PresetAutoSigRoutesButton->Enabled = true;
14925  InfoPanel->Visible = true;
14926  SigImagePanel->Visible = false; // new at v2.3.0
14927  ModeMenu->Enabled = false;
14928  FileMenu->Enabled = false;
14929  EditMenu->Enabled = false;
14930  ImageMenu->Enabled = true;
14931  SaveImageAndGridMenuItem->Enabled = true;
14932  SaveImageNoGridMenuItem->Enabled = true;
14933  if(EveryPrefDir->PrefDirSize() > 0)
14934  {
14935  SaveImageAndPrefDirsMenuItem->Enabled = true;
14936  }
14937  else
14938  {
14939  SaveImageAndPrefDirsMenuItem->Enabled = false;
14940  }
14941  SaveOperatingImageMenuItem->Enabled = true;
14942  AutoSigsFlag = false;
14943  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
14945  {
14946  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
14947  }
14948  else
14949  {
14950  MTBFEditBox->Text = "";
14951  }
14952  MTBFEditBox->ReadOnly = false; // because this is prestart mode
14953  MTBFLabel->Visible = true;
14954  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14956  if(EveryPrefDir->PrefDirSize() > 0)
14957  {
14958  ConsecSignalsRoute = true; // default starting conditions
14959  PreferredRoute = true; // default starting conditions
14960  }
14961  else // no PrefDirs
14962  {
14963  ConsecSignalsRoute = false;
14964  PreferredRoute = false;
14965  }
14966  OperateButton->Enabled = true;
14967  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
14968  ExitOperationButton->Enabled = true;
14969  TTClockAdjButton->Enabled = true;
14970  ShowPerformancePanel = false;
14971  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
14972  ShowOperatorActionPanel = false; // new at v2.2.0
14973  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
14974 
14976 
14977  Utilities->Clock2Stopped = false;
14981  TTClockSpeed = 1;
14982  TTClockSpeedLabel->Caption = "x1";
14985 
14986  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
14987  // format "16/06/2009 20:55:17"
14988  // avoid characters in filename:= / \ : * ? " < > |
14989  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
14990 
14991  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
14992  if(Utilities->PerformanceFile.fail())
14993  {
14994  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
14995  " in the folder where the 'Railway.exe' program file resides");
14996  }
14998 // DisableRouteButtons(2); enable route setting or pre-start
14999 // DisablePanelsStoreMainMenuStates();
15000  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
15001  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
15002 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
15003 
15004 // reset all performance indicators
15013  TrainController->OnTimeExits = 0; //these 3 exits added at v2.9.2 - missed in error earlier
15033 
15034  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
15035  OAListBox->Clear();
15036  OAListBox->Items->Add(L""); // hints for OpActionPanel
15037  OAListBox->Items->Add(L"");
15038  OAListBox->Items->Add(L"");
15039  OAListBox->Items->Add(L"Left click");
15040  OAListBox->Items->Add(L"headcode to");
15041  OAListBox->Items->Add(L"locate train");
15042  OAListBox->Items->Add(L"");
15043  OAListBox->Items->Add(L"");
15044  OAListBox->Items->Add(L"Right click");
15045  OAListBox->Items->Add(L"headcode for");
15046  OAListBox->Items->Add(L"information");
15047  OAListBox->Items->Add(L"");
15048  OAListBox->Items->Add(L"");
15049  OAListBox->Items->Add(L"Left click and");
15050  OAListBox->Items->Add(L"hold grey area");
15051  OAListBox->Items->Add(L"to move panel");
15052 
15053  ClearandRebuildRailway(55); // so points display with one fillet
15054  break;
15055 
15056  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
15057  Level1Mode = OperMode;
15058 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
15061  OperatingPanel->Visible = true;
15062  OperatingPanelLabel->Caption = "Operation";
15063 
15064  CallingOnButton->Visible = true;
15065  PresetAutoSigRoutesButton->Visible = false;
15066  InfoPanel->Visible = true;
15067  ModeMenu->Enabled = false;
15068  SigImagePanel->Visible = false; // new at v2.3.0
15069  FileMenu->Enabled = false;
15070  EditMenu->Enabled = false;
15071  ImageMenu->Enabled = true;
15072  SaveImageAndGridMenuItem->Enabled = true;
15073  SaveImageNoGridMenuItem->Enabled = true;
15074  if(EveryPrefDir->PrefDirSize() > 0)
15075  {
15076  SaveImageAndPrefDirsMenuItem->Enabled = true;
15077  }
15078  else
15079  {
15080  SaveImageAndPrefDirsMenuItem->Enabled = false;
15081  }
15082  SaveOperatingImageMenuItem->Enabled = true;
15083 
15084  OperateButton->Enabled = true;
15085  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
15086  ExitOperationButton->Enabled = true;
15087  TTClockAdjButton->Enabled = true;
15090  if(Level2OperMode == Paused)
15091  {
15092  DisableRouteButtons(3); // could be PreStart or Paused
15093  }
15098  TTClockSpeed = 1;
15099  TTClockSpeedLabel->Caption = "x1";
15101  ShowPerformancePanel = false; // added at v2.2.0
15102  ShowOperatorActionPanel = false; // new at v2.2.0
15103  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
15104  OAListBox->Clear();
15105  OAListBox->Items->Add(L""); // hints for OpActionPanel
15106  OAListBox->Items->Add(L"");
15107  OAListBox->Items->Add(L"");
15108  OAListBox->Items->Add(L"Left click");
15109  OAListBox->Items->Add(L"headcode to");
15110  OAListBox->Items->Add(L"locate train");
15111  OAListBox->Items->Add(L"");
15112  OAListBox->Items->Add(L"");
15113  OAListBox->Items->Add(L"Right click");
15114  OAListBox->Items->Add(L"headcode for");
15115  OAListBox->Items->Add(L"information");
15116  OAListBox->Items->Add(L"");
15117  OAListBox->Items->Add(L"");
15118  OAListBox->Items->Add(L"Left click and");
15119  OAListBox->Items->Add(L"hold grey area");
15120  OAListBox->Items->Add(L"to move panel");
15121  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
15122  {
15123  MTBFEditBox->Visible = true;
15125  {
15126  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
15127  }
15128  else
15129  {
15130  MTBFEditBox->Text = "";
15131  }
15132  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
15133  MTBFLabel->Visible = true;
15134  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
15136  }
15137  else
15138  {
15139  MTBFEditBox->Visible = false;
15140  MTBFEditBox->Text = "";
15141  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
15142  MTBFLabel->Visible = false;
15143  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
15145  }
15146  break;
15147 
15148  default:
15149  // No further recursion in BaseMode so OK
15150  Level1Mode = BaseMode;
15151  SetLevel1Mode(29);
15152  break;
15153  }
15154  Utilities->CallLogPop(103);
15155 }
15156 
15157 // ---------------------------------------------------------------------------
15158 
15160 {
15161  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
15162  if(Level1Mode != TrackMode)
15163  {
15164  // No further recursion in BaseMode so OK
15165  Level1Mode = BaseMode;
15166  SetLevel1Mode(20);
15167  Utilities->CallLogPop(1115);
15168  return;
15169  }
15171  {
15172  Utilities->CallLogPop(104);
15173  return;
15174  }
15175  switch(Level2TrackMode) // use the data member
15176  {
15177  case AddTrack:
15179  InfoPanel->Visible = true;
15180  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
15181  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
15182  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
15183  TrackElementPanel->Visible = true;
15184  TrackElementPanel->Enabled = true;
15185  SigAspectButton->Visible = true;
15186  SigAspectButton->Enabled = true;
15187  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
15189  SetLengthsButton->Enabled = false;
15190 // section added at v2.8.0 so buttons show correctly after a paste
15191  SetGapsButton->Enabled = false;
15192  TrackOKButton->Enabled = false;
15193  if(Track->GapsUnset(9))
15194  {
15195  SetGapsButton->Enabled = true;
15196  }
15197  // only enable if there are gaps still to be set (returns false for no track)
15198  else
15199  {
15200  if(!(Track->NoActiveTrack(3)) && !(Track->IsTrackFinished()))
15201  {
15202  TrackOKButton->Enabled = true;
15203  }
15204  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
15205  }
15206 // end of 2.8.0 addition
15207  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
15208  {
15209  SetLengthsButton->Enabled = true;
15210  }
15211  UserGraphicReselectPanel->Visible = false;
15212  SelectLengthsFlag = false; // in case still set though probably won't be
15213  EditMenu->Enabled = true; // added at v2.6.0 to allow edits for an empty screen so track elements can fill a selected area
15214  break;
15215 
15216  case AddGraphic:
15217  InfoPanel->Visible = true;
15218  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
15219  break;
15220 
15221  case SelectGraphic:
15222  InfoPanel->Visible = true;
15223  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
15224  break;
15225 
15226  case GapSetting:
15227  int HLoc, VLoc, Count;
15228  Count = Track->NumberOfGaps(0);
15229  if(div(Count, 2).rem == 1) // condition OK
15230  {
15231  ShowMessage("Can't connect, there are an odd number of gaps");
15233  SetLevel1Mode(77);
15235  // No further recursion in AddTrack so OK
15236  SetLevel2TrackMode(40);
15237  Utilities->CallLogPop(105);
15238  return;
15239  }
15240  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
15241  // need to call this here to start gap setting process off,
15242  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
15243  // complete) or no more gaps to be highlighted
15244  {
15245  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
15246  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
15248  SetLevel1Mode(78);
15250  // No further recursion in AddTrack so OK
15251  SetLevel2TrackMode(41);
15252  Utilities->CallLogPop(106);
15253  return; // all gaps set
15254  }
15255  InfoPanel->Visible = true;
15256  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
15257  UserGraphicReselectPanel->Visible = false;
15259  break;
15260 
15261  case AddText:
15262  InfoPanel->Visible = true;
15263  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
15264  if(TextHandler->TextVectorSize(13) > 0)
15265  {
15266  MoveTextOrGraphicButton->Enabled = true;
15267  }
15268  else
15269  {
15270  MoveTextOrGraphicButton->Enabled = false;
15271  }
15272  UserGraphicReselectPanel->Visible = false;
15273  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
15274  break;
15275 
15276  case MoveTextOrGraphic:
15277  InfoPanel->Visible = true;
15278  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
15279  UserGraphicReselectPanel->Visible = false;
15280  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
15281  break;
15282 
15283  case AddLocationName:
15284  InfoPanel->Visible = true;
15285  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
15286  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
15287  UserGraphicReselectPanel->Visible = false;
15288  SetTrackBuildImages(12);
15289  break;
15290 
15291  case DistanceStart:
15292  InfoPanel->Visible = true;
15293  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
15294  DistanceKey->Visible = true;
15295  LengthConversionPanel->Visible = true;
15296  SpeedConversionPanel->Visible = true;
15297  UserGraphicReselectPanel->Visible = false;
15298  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
15299  break;
15300 
15301  case DistanceContinuing:
15302  InfoPanel->Visible = true;
15303  if(ConstructPrefDir->PrefDirSize() == 1)
15304  {
15305  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
15306  }
15307  else
15308  {
15309  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
15310  }
15311  UserGraphicReselectPanel->Visible = false;
15312  ClearandRebuildRailway(54); // to remove earlier end marker if present
15313  break;
15314 
15315  case TrackSelecting:
15316  Track->CopyFlag = false;
15317  if(!SelectionValid)
15318  {
15319  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
15320  }
15321  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
15322  // ReselectMenuItemClick)
15323  InfoPanel->Visible = true;
15324  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
15325  SelectMenuItem->Enabled = false;
15326  ReselectMenuItem->Enabled = false;
15327  CancelSelectionMenuItem->Enabled = true;
15328  UserGraphicReselectPanel->Visible = false;
15329  break;
15330 
15331  case CopyMoving:
15332  Track->CopyFlag = true;
15333  InfoPanel->Visible = true;
15334  InfoPanel->Caption = "COPYING: Left click in selection && drag";
15335  CutMenuItem->Enabled = false;
15336  CopyMenuItem->Enabled = false;
15337  FlipMenuItem->Enabled = false;
15338  MirrorMenuItem->Enabled = false;
15339  RotRightMenuItem->Enabled = false;
15340  RotLeftMenuItem->Enabled = false;
15341  RotateMenuItem->Enabled = false;
15342  PasteMenuItem->Enabled = true;
15343 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying (dropped at 2.4.0 as all pastes are with attributes)
15344  DeleteMenuItem->Enabled = false;
15345  SelectLengthsMenuItem->Enabled = false;
15346  SelectBiDirPrefDirsMenuItem->Visible = false;
15347  CheckPrefDirConflictsMenuItem->Visible = false;
15348  CancelSelectionMenuItem->Enabled = true;
15352  UserGraphicReselectPanel->Visible = false;
15353  break;
15354 
15355  case CutMoving:
15356  {
15357  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15358  // erase track elements within selected region
15359  Track->CopyFlag = false;
15360  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
15361  int ErasedTrackVectorPosition;
15362  Screen->Cursor = TCursor(-11); // Hourglass;
15363  InfoPanel->Visible = true;
15364  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
15365  InfoPanel->Update();
15366  for(int H = SelectRect.left; H < SelectRect.right; H++)
15367  {
15368  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
15369  {
15370  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
15371  if(EraseSuccessfulFlag)
15372  {
15373  if(ErasedTrackVectorPosition > -1) //may be an inactive element that was erased
15374  {
15375  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
15376  }
15377  NeedToLink = true;
15378  }
15379  }
15380  }
15381 
15382  // erase text elements within selected region
15383  int LowSelectHPos = SelectRect.left * 16;
15384  int HighSelectHPos = SelectRect.right * 16;
15385  int LowSelectVPos = SelectRect.top * 16;
15386  int HighSelectVPos = SelectRect.bottom * 16;
15387  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
15388  {
15389  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
15390  TextPtr--) // reverse to prevent skipping during erase
15391  {
15392  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
15393  HighSelectVPos))
15394  {
15395  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
15396  {
15397  ;
15398  } // unused condition
15399 
15400  TextChangesMade = true;
15401  }
15402  }
15403  }
15404  // erase graphic elements that fall wholly within region to be overwritten
15405  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
15406  {
15407  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
15408  GraphicPtr--) // reverse to prevent skipping during erase
15409  {
15410  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
15411  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
15412  {
15413  Track->UserGraphicVector.erase(GraphicPtr);
15414  GraphicChangesMade = true;
15415  }
15416  }
15417  }
15418  Track->CheckMapAndTrack(11); // test
15419  Track->CheckMapAndInactiveTrack(10); // test
15420  Track->CheckLocationNameMultiMap(19); // test
15421  Screen->Cursor = TCursor(-2); // Arrow;
15422  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
15423  // if track not linked to begin with then becomes linked if NeedToLink false
15424  if(NeedToLink)
15425  {
15426  Track->SetTrackFinished(false); // corrected for v2.1.0
15427  }
15428  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
15429  CutMenuItem->Enabled = false;
15430  CopyMenuItem->Enabled = false;
15431  FlipMenuItem->Enabled = false;
15432  MirrorMenuItem->Enabled = false;
15433  RotRightMenuItem->Enabled = false;
15434  RotLeftMenuItem->Enabled = false;
15435  RotateMenuItem->Enabled = false;
15436  PasteMenuItem->Enabled = true;
15437 // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting (dropped at 2.4.0 as all pastes are with attributes)
15438  DeleteMenuItem->Enabled = false;
15439  SelectLengthsMenuItem->Enabled = false;
15440  SelectBiDirPrefDirsMenuItem->Visible = false;
15441  CheckPrefDirConflictsMenuItem->Visible = false;
15442  CancelSelectionMenuItem->Enabled = true;
15445  if(NeedToLink || TextChangesMade || GraphicChangesMade)
15446  {
15447  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
15448  }
15449  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
15450  UserGraphicReselectPanel->Visible = false;
15452  } break;
15453 
15454  case Pasting:
15455  {
15456  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15457  int HDiff = SelectBitmapHLoc - SelectRect.left; // SelectBitmapHLoc/VLoc is the paste position & SelectRect.left/top is the original position
15458  int VDiff = SelectBitmapVLoc - SelectRect.top;
15459  if(!SelectionValid && !CancelSelectionFlag) // may be pasting into a new application so use clipboard, new at v2.8.0
15460  {
15461  bool ValidResult;
15462  RecoverClipboard(0, ValidResult); // new at v2.8.0
15463  if(ValidResult)
15464  {
15465  HDiff = Display->DisplayOffsetH - SelectRect.left; // SelectRect.left & top recovered in clipboard
15466  VDiff = Display->DisplayOffsetV - SelectRect.top;
15467  SelectBitmapHLoc = Display->DisplayOffsetH; // so the area to erase corresponds to the paste area (TLHC of screen = DisplayOffsetH & V)
15469  SelectionValid = false; // don't want reselect in new app after paste
15470  Track->SetTrackFinished(false); // would be set to false in other app but not in this so set it to false here
15472  {
15473  UnicodeString MessageStr =
15474  "Please be aware of the relevant conditions when pasting " "a railway segment from a different application.\n"
15475  "These are set out in section 3.5 of the manual and " "on-screen help under the heading 'Pasting in an application "
15476  "after cutting or copying from a different application'.\n\n" "This warning will not be shown again.\n\n" "Proceed?";
15477  int button = Application->MessageBox(MessageStr.c_str(), L"Warning", MB_YESNO | MB_ICONWARNING);
15479  if(button == IDNO)
15480  {
15481  CancelSelectionMenuItem->Click(); // reset clipboard etc
15482  Utilities->CallLogPop(2271);
15483  return;
15484  }
15485  }
15486  }
15487  else
15488  {
15489  Application->MessageBoxW(L"Unable to paste, clipboard is corrupt or does not contain a valid railway segment", L"Warning", MB_OK | MB_ICONWARNING);
15490  CancelSelectionMenuItem->Click(); // reset clipboard etc
15491  Utilities->CallLogPop(2272);
15492  return;
15493  }
15494  }
15495  if(CancelSelectionFlag) // plot cut area in original position in case moved
15496  {
15499  HDiff = 0;
15500  VDiff = 0;
15501  }
15502  Clipboard()->Clear(); // already cleared & closed if recovered clipboard but not otherwise so clear & close here
15503  Clipboard()->Close();
15506  bool NeedToLink = false;
15507  bool TrackLinkingRequiredFlag;
15508  Screen->Cursor = TCursor(-11); // Hourglass;
15509  InfoPanel->Visible = true;
15510  InfoPanel->Caption = "PASTING: Please wait";
15511  InfoPanel->Update();
15512 // erase track elements
15513  int LowSelectHLoc = SelectBitmapHLoc;
15514  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
15515  int LowSelectVLoc = SelectBitmapVLoc;
15516  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
15517  bool TrackEraseSuccessfulFlag; // needed but not used here
15518  int ErasedTrackVectorPosition;
15519 // new quick method of erasing, only need H & V values
15520  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
15521  {
15522  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
15523  {
15524  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
15525  if(ErasedTrackVectorPosition > -1)
15526  {
15527  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
15528  }
15529  }
15530  }
15531 
15532 // erase text elements that fall within region to be overwritten
15533  int LowSelectHPos = SelectBitmapHLoc * 16;
15534  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
15535  int LowSelectVPos = SelectBitmapVLoc * 16;
15536  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
15537  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
15538  {
15539  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
15540  TextPtr--) // reverse to prevent skipping during erase
15541  {
15542  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
15543  HighSelectVPos))
15544  {
15545  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
15546  {
15547  ;
15548  } // unused condition
15549 
15550  }
15551  }
15552  }
15553 // erase graphic elements that fall wholly within region to be overwritten
15554  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
15555  {
15556  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
15557  GraphicPtr--) // reverse to prevent skipping during erase
15558  {
15559  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
15560  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
15561  {
15562  Track->UserGraphicVector.erase(GraphicPtr);
15563  }
15564  }
15565  }
15566  // change the H & V values in SelectVector to the new positions in case Reselect chosen
15567  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
15568  {
15569  Track->SelectVectorAt(35, x).HLoc += HDiff;
15570  Track->SelectVectorAt(1, x).VLoc += VDiff;
15571  }
15572 
15573  // add the new track elements
15574  AnsiString LocName;
15575  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
15576  {
15577  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
15578  {
15579  Track->SelectVectorAt(80, x).LocationName = "";
15581  }
15582  else //cut, check if element has a name and if so remove same existing name from name map and track vector
15583  {
15584  LocName = Track->SelectVectorAt(82, x).LocationName;
15585  if(LocName == "")
15586  {
15587  LocName = Track->SelectVectorAt(83, x).ActiveTrackElementName;
15588  }
15589  if(LocName != "")
15590  {
15591  Track->EraseLocationAndActiveTrackElementNames(6, LocName); //this will keep erasing adjacent element names but the last one will be pasted and not erased
15592  //and that will name all linked elements so should work ok
15593  int HPos = 0, VPos = 0;
15594  if(TextHandler->FindText(5, LocName, HPos, VPos))
15595  {
15596  ;
15597  }
15598  {
15599  if(EraseLocationNameText(4, LocName, HPos, VPos))
15600  {
15601  ;
15602  } // condition not used
15603  }
15604  }
15605  }
15606  bool InternalChecks = false;
15607 // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
15608 // {
15610  TrackLinkingRequiredFlag, InternalChecks);
15611  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
15612 // }
15613 /* drop this in v2.4.0 as all pastes are with attributes
15614  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
15615  {
15616  int Aspect;
15617  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
15618  //this combination allows the funtion to distinguish between adding track and plotting with attributes
15619  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
15620  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
15621  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
15622  else Aspect = 4;
15623  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
15624  }
15625 */
15626  if(TrackLinkingRequiredFlag)
15627  {
15628  NeedToLink = true;
15629  }
15630  }
15631 
15632  //add the pref dir elements, added at v2.9.0
15633  int ATVecPos;
15634  bool FoundFlag;
15635  if(SelectPrefDir->PrefDirSize() > 0) // skip iteration if empty
15636  {
15637  // keep contents valid in case reselect
15639  PDVIt++)
15640  {
15641  PDVIt->HLoc += HDiff; // for reselect
15642  PDVIt->VLoc += VDiff; // for reselect
15643  //need to reset TrackVectorPosition in case any elements erased before linking, as if so EveryPrefDir can only be erased too if it has the correct TrackVectorPosition
15644  ATVecPos = Track->GetVectorPositionFromTrackMap(60, PDVIt->HLoc, PDVIt->VLoc, FoundFlag);
15645  if(!FoundFlag)
15646  {
15647  throw Exception("Failed to find TrackVectorPosition in PrefDir setting for Paste");
15648  }
15649  PDVIt->SetTrackVectorPosition(ATVecPos);
15650 
15651  //reset all Conns & ConnLinkPos values so won't be erased during a later cut, they will be set in RebuildPrefDirVector which is called when track linked
15652  for(int x = 0; x < 4; x++)
15653  {
15654  PDVIt->Conn[x] = -1;
15655  PDVIt->ConnLinkPos[x] = -1;
15656  }
15658  }
15660  }
15661 
15662  // add the new text items
15663  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
15664  {
15665  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
15666  {
15667  TextPtr->HPos += HDiff * 16;
15668  TextPtr->VPos += VDiff * 16;
15669  AnsiString TempString = TextPtr->TextString;
15670  // have to create a new TextItem in order to create a new Font object
15671 /* drop in v2.4.0 as all pastes are paste with attributes
15672  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
15673  {
15674  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
15675  //use in PastingWithAttributes
15676  {
15677  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
15678  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
15679  }
15680  else TextPtr->TextString = ""; //delete the name for a simple paste
15681  }
15682 */
15683 // else //if pasting with attributes paste all text but strip the '##**' prefix if present
15684 // {
15685  if(TextPtr->TextString.SubString(1, 4) == "##**")
15686  {
15687  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
15688  if(Track->CopyFlag)
15689  {
15690  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
15691  TempString = "";
15692  }
15693  }
15694  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
15696 // }
15697  }
15698  }
15699  // add new graphic items
15700  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
15701  {
15702  // keep contents of SelectVector valid in case reselect
15703  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
15704  GraphicPtr++)
15705  {
15706  GraphicPtr->HPos += HDiff * 16; // for reselect
15707  GraphicPtr->VPos += VDiff * 16; // for reselect
15708  Track->UserGraphicVector.push_back(*GraphicPtr);
15709  }
15710  }
15711  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
15712  Track->CopyFlag = false;
15713  Track->CheckMapAndTrack(7); // test
15714  Track->CheckMapAndInactiveTrack(7); // test
15715  Track->CheckLocationNameMultiMap(7); // test
15716  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
15717  // if track not linked to begin with then becomes linked if NeedToLink false
15718  if(NeedToLink)
15719  {
15720  Track->SetTrackFinished(false); // corrected for v2.1.0
15721  }
15722  Screen->Cursor = TCursor(-2); // Arrow;
15723  SetTrackBuildImages(14);
15725  // Level1Mode = TrackMode; //dropped as prevents AddTrack being called to display track elements
15726  // SetLevel1Mode(79);
15727  SetTrackModeEditMenu(5); // this is called from the above but is still needed to enable Select (& Reselect if pasted in same app) menu items
15728  PasteMenuItem->Enabled = false;
15729  UserGraphicReselectPanel->Visible = false;
15730  if(Level2TrackMode != AddTrack) // no need to set if already set in an earlier call
15731  {
15733  // No further recursion in AddTrack so OK
15734  SetLevel2TrackMode(42);
15735  }
15736  } break;
15737 
15738  case Deleting:
15739  {
15740  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15741  Track->CopyFlag = false;
15742  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
15743  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
15744  if(button == IDNO)
15745  {
15746  break;
15747  }
15748  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
15749  int ErasedTrackVectorPosition;
15750  Screen->Cursor = TCursor(-11); // Hourglass;
15751  InfoPanel->Visible = true;
15752  InfoPanel->Caption = "DELETING: Please wait";
15753  InfoPanel->Update();
15754  for(int H = SelectRect.left; H < SelectRect.right; H++)
15755  {
15756  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
15757  {
15758  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
15759  if(EraseSuccessfulFlag)
15760  {
15761  if(ErasedTrackVectorPosition > -1)
15762  {
15763  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
15764  }
15765  NeedToLink = true;
15766  }
15767  }
15768  }
15769  // erase text elements that fall within selected region
15770  int LowSelectHPos = SelectRect.left * 16;
15771  int HighSelectHPos = SelectRect.right * 16;
15772  int LowSelectVPos = SelectRect.top * 16;
15773  int HighSelectVPos = SelectRect.bottom * 16;
15774  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
15775  {
15776  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
15777  TextPtr--) // reverse to prevent skipping during erase
15778  {
15779  AnsiString Check = TextPtr->TextString;
15780  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
15781  HighSelectVPos))
15782  {
15783  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
15784  {
15785  ;
15786  } // unused condition
15787 
15788  TextChangesMade = true;
15789  }
15790  }
15791  }
15792  // erase graphic elements that fall within selected region
15793  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
15794  {
15795 
15796 // Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
15797 
15798 // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
15799 // GraphicPtr--) // reverse to prevent skipping during erase
15800 
15801 // i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
15802 // corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
15803 
15804  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
15805  GraphicPtr--) // reverse to prevent skipping during erase
15806  {
15807  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
15808  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
15809  {
15810  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
15811  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
15812  {
15813  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
15814  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
15815  (UserGraphicPtr->FileName == GraphicPtr->FileName))
15816  {
15817  Track->UserGraphicVector.erase(UserGraphicPtr);
15818  GraphicChangesMade = true;
15819  }
15820  }
15821  }
15822  }
15823  }
15824  // clear the selectvectors
15826  TextHandler->SelectTextVector.clear();
15827  Track->SelectGraphicVector.clear();
15829  Track->CheckMapAndTrack(10); // test
15830  Track->CheckMapAndInactiveTrack(9); // test
15831  Track->CheckLocationNameMultiMap(15); // test
15832  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
15833  // if track not linked to begin with then becomes linked if NeedToLink false
15834  if(NeedToLink)
15835  {
15836  Track->SetTrackFinished(false); // corrected for v2.1.0
15837  }
15838  if(NeedToLink || TextChangesMade || GraphicChangesMade)
15839  {
15840  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
15841  }
15842  Screen->Cursor = TCursor(-2); // Arrow;
15845  SetLevel1Mode(80);
15847  // No further recursion in AddTrack so OK
15848  UserGraphicReselectPanel->Visible = false;
15849  SetLevel2TrackMode(43);
15850  } break;
15851 
15852  default:
15853  // No further recursion in TrackMode so OK
15854  Track->CopyFlag = false;
15856  SetLevel1Mode(21);
15857  UserGraphicReselectPanel->Visible = false;
15858  break;
15859  }
15860  Utilities->CallLogPop(107);
15861 }
15862 
15863 // ---------------------------------------------------------------------------
15864 
15866 {
15867  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
15868  if(Level1Mode != PrefDirMode)
15869  {
15870  // No further recursion in BaseMode so OK
15871  Level1Mode = BaseMode;
15872  SetLevel1Mode(22);
15873  Utilities->CallLogPop(108);
15874  return;
15875  }
15877  {
15878  Utilities->CallLogPop(109);
15879  return;
15880  }
15881  switch(Level2PrefDirMode) // use the data member
15882  {
15883  case PrefDirContinuing:
15884  {
15885  // have to use braces as otherwise the default case bypasses the initialisation of these local variables
15886  InfoPanel->Visible = true;
15887  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
15888  {
15889  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
15890  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
15891  }
15892  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
15893  DeleteOnePrefDirButton->Enabled = false;
15894  bool LeadingPointsAtLastElement = false;
15895  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
15896  {
15897  if(LeadingPointsAtLastElement) // size must be > 1
15898  {
15899  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
15900  DeleteOnePrefDirButton->Enabled = true;
15901  }
15902  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
15903  {
15904  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
15905  }
15906  }
15907  else // size > 1 & EndPossible
15908  {
15909  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
15910  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
15911  {
15912  AddPrefDirButton->Enabled = true;
15913  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
15914  }
15915  DeleteOnePrefDirButton->Enabled = true;
15916  }
15917  ExitPrefDirButton->Enabled = true;
15918  ClearandRebuildRailway(40); // to show truncated PrefDirs
15919  } break;
15920 
15921  case PrefDirSelecting:
15922  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
15923  InfoPanel->Visible = true;
15924  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
15925  SelectMenuItem->Enabled = false;
15926  ReselectMenuItem->Enabled = false;
15927  CancelSelectionMenuItem->Enabled = true;
15928  break;
15929 
15930  default:
15931  // No further recursion in PrefDirMode so OK
15933  SetLevel1Mode(23);
15934  break;
15935  }
15936  Utilities->CallLogPop(110);
15937 }
15938 
15939 // ---------------------------------------------------------------------------
15940 
15942 {
15943  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
15944  if(Level1Mode != OperMode)
15945  {
15946  // No further recursion in BaseMode so OK
15947  Level1Mode = BaseMode;
15948  SetLevel1Mode(24);
15949  Utilities->CallLogPop(111);
15950  return;
15951  }
15952  if(Level2OperMode == NoOperMode)
15953  {
15954  Utilities->CallLogPop(112);
15955  return;
15956  }
15957  CallingOnButton->Visible = true;
15958  PresetAutoSigRoutesButton->Visible = false;
15959  switch(Level2OperMode) // use the data member
15960  {
15961  case Operating:
15962  {
15963  // have to use braces as otherwise the default case bypasses the initialisation of local variables
15964  OperateButton->Enabled = true;
15965  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
15966  ExitOperationButton->Enabled = true;
15967  TTClockAdjButton->Enabled = false;
15968  if(TTClockSpeed == 2)
15969  {
15970  TTClockSpeedLabel->Caption = "x2";
15971  }
15972  else if(TTClockSpeed == 4)
15973  {
15974  TTClockSpeedLabel->Caption = "x4";
15975  }
15976  else if(TTClockSpeed == 8)
15977  {
15978  TTClockSpeedLabel->Caption = "x8";
15979  }
15980  else if(TTClockSpeed == 16)
15981  {
15982  TTClockSpeedLabel->Caption = "x16";
15983  }
15984  else if(TTClockSpeed == 0.5)
15985  {
15986  TTClockSpeedLabel->Caption = "x1/2";
15987  }
15988  else if(TTClockSpeed == 0.25)
15989  {
15990  TTClockSpeedLabel->Caption = "x1/4";
15991  }
15992  else if(TTClockSpeed == 0.125)
15993  {
15994  TTClockSpeedLabel->Caption = "x1/8";
15995  }
15996  else if(TTClockSpeed == 0.0625)
15997  {
15998  TTClockSpeedLabel->Caption = "x1/16";
15999  }
16000  else
16001  {
16002  TTClockSpeed = 1;
16003  TTClockSpeedLabel->Caption = "x1";
16004  }
16005  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
16007  {
16008  // send message to performance log
16009  if(TTClockSpeed == 2)
16010  {
16011  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
16012  }
16013  else if(TTClockSpeed == 4)
16014  {
16015  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
16016  }
16017  else if(TTClockSpeed == 8)
16018  {
16019  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
16020  }
16021  else if(TTClockSpeed == 16)
16022  {
16023  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
16024  }
16025  else if(TTClockSpeed == 0.5)
16026  {
16027  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
16028  }
16029  else if(TTClockSpeed == 0.25)
16030  {
16031  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
16032  }
16033  else if(TTClockSpeed == 0.125)
16034  {
16035  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
16036  }
16037  else if(TTClockSpeed == 0.0625)
16038  {
16039  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
16040  }
16041  else
16042  {
16043  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
16044  }
16045  }
16046  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
16047  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
16048  {
16049  // send message to performance log
16050  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
16051  int HoursIncrease = 0;
16052  while(MinsIncrease >= 60)
16053  {
16054  HoursIncrease++;
16055  MinsIncrease -= 60;
16056  }
16057  if(HoursIncrease == 0)
16058  {
16059  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
16060  }
16061  else if(MinsIncrease == 0)
16062  {
16063  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
16064  }
16065  else
16066  {
16067  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
16068  }
16069  Display->PerformanceLog(13, TimeMessage);
16070  }
16071  WarningHover = false;
16074  {
16075  MTBFEditBox->Visible = true;
16076  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
16077  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
16078  MTBFLabel->Visible = true;
16079  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16081  }
16082  else
16083  {
16084  MTBFEditBox->Visible = false;
16085  MTBFEditBox->Text = "";
16086  MTBFLabel->Visible = false;
16087  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
16089  }
16090  TrainController->BaseTime = TDateTime::CurrentDateTime();
16091 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
16092  } break;
16093 
16094  case Paused:
16095  OperateButton->Enabled = true;
16096  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
16097  ExitOperationButton->Enabled = true;
16098  TTClockAdjButton->Enabled = true;
16103 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
16106  break;
16107 
16108  // don't need a separate case for PreStart
16109 
16110  default:
16111  // No further recursion in OperMode so OK
16112  Level1Mode = OperMode;
16113  SetLevel1Mode(25);
16114  break;
16115  }
16116  Utilities->CallLogPop(113);
16117 }
16118 
16119 // ---------------------------------------------------------------------------
16120 
16121 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
16122 {
16123  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
16124  float LockDelay = 120.0;
16125 
16126  if(!AllRoutes->LockedRouteVector.empty())
16127  {
16128  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
16129  {
16130  bool BreakFlag = false;
16131  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
16132  {
16133  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
16134  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
16135  {
16136  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
16137  AnsiString(LRVIT->LastTrackVectorPosition));
16138  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
16139  {
16140  // examine the element one earlier in the route than the last
16141  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
16142  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
16143  {
16144  BreakFlag = true;
16145  }
16146  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
16147  if(BreakFlag)
16148  {
16149  break; // train removed earlier element from route so stop here
16150  }
16151  }
16152  if(!BreakFlag)
16153  {
16154  // still need to remove the element at the TruncateTrackVectorPosition
16155  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
16156  {
16157  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
16158  Route.LastElementPtr(20)->GetELink());
16159  }
16160  }
16161  AllRoutes->CheckMapAndRoutes(10); // test
16162  AllRoutes->LockedRouteVector.erase(LRVIT);
16163  if(!Display->ZoomOutFlag)
16164  {
16165  ClearandRebuildRailway(17); // to get rid of route graphics
16166  }
16168  }
16169  }
16170  else
16171  {
16172  AllRoutes->LockedRouteVector.erase(LRVIT);
16173  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
16174  // hence no longer needed so get rid of it
16175  }
16176  }
16177  }
16178  Utilities->CallLogPop(743);
16179 }
16180 
16181 // ---------------------------------------------------------------------------
16182 
16183 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
16184 {
16185  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
16187  {
16189  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16190  AutoSigVectorIT--)
16191  {
16192  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
16193  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
16194  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
16195  TPrefDirElement TempPrefDirElement;
16196  int TempLockedVectorNumber;
16197  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
16198  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
16199  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
16200  // route exiting at a continuation
16201  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
16202  {
16203  continue;
16204  }
16205  // end of additions
16206  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
16207  {
16208  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
16209  AutoSigVectorIT->AccessNumber++;
16210  continue;
16211  }
16212  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
16213  {
16214  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
16215  AutoSigVectorIT->AccessNumber++;
16216  continue;
16217  }
16218  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
16219  {
16220  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
16221  AutoSigVectorIT->AccessNumber++;
16222  continue;
16223  }
16224  }
16225  // examine all vector for any expired values & erase
16226  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16227  AutoSigVectorIT--)
16228  {
16229  if(AutoSigVectorIT->AccessNumber > 2)
16230  {
16231  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
16232  }
16233  }
16234  }
16235  Utilities->CallLogPop(744);
16236 }
16237 
16238 // ---------------------------------------------------------------------------
16239 
16241 {
16242  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
16243  TPoint MousePoint = Mouse->CursorPos;
16244  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
16245  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
16246 
16247  if(!OAListBoxRightMouseButtonDown && ((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0)))
16248  {
16249  // added !OAListBoxRightMouseButtonDown at v2.7.0 so can still obtain info & move to trains from OAListBox even if they are out of the main screen area
16250  FloatingPanel->Visible = false;
16251  Utilities->CallLogPop(1432);
16252  return;
16253  }
16254  if(PerformancePanel->Visible)
16255  {
16256  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
16257  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
16258  (PerformancePanel->Top + PerformancePanel->Height)))
16259  {
16260  // dont show floating window if mouse over performance panel
16261  FloatingPanel->Visible = false;
16262  Utilities->CallLogPop(1715);
16263  return;
16264  }
16265  }
16266  if(TimetableEditPanel->Visible) // added at v2.5.1 as showed track info behind panel
16267  {
16268  if((MousePoint.x >= TimetableEditPanel->Left) && (MousePoint.x <= (TimetableEditPanel->Left + TimetableEditPanel->Width)) &&
16269  ((MousePoint.y - ClientOrigin.y) >= TimetableEditPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
16270  (TimetableEditPanel->Top + TimetableEditPanel->Height)))
16271  {
16272  // dont show floating window if mouse over TimetableEditPanel
16273  FloatingPanel->Visible = false;
16274  Utilities->CallLogPop(2240);
16275  return;
16276  }
16277  }
16278  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
16279  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
16280  int HLoc, VLoc;
16281 
16282  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
16283 
16284  if(Display->ZoomOutFlag)
16285  {
16286  Utilities->CallLogPop(1123);
16287  return;
16288  }
16289  bool MouseOverOAPanel = false;
16290 // this flag added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
16291  if(OperatorActionPanel->Visible)
16292  {
16293  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
16294  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
16295  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
16296  {
16297  MouseOverOAPanel = true;
16298  }
16299  }
16300  if((TrackInfoOnOffMenuItem->Caption == "Hide") && !MouseOverOAPanel)
16301  // MouseOverOAPanel condit added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
16302  {
16303  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
16304  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
16305  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
16306  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
16307  AnsiString SigAspectString = ""; // new at version 0.6
16308  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
16309  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
16310  TTrackElement ActiveTrackElement, InactiveTrackElement;
16311  if(InactiveTrackFoundFlag)
16312  {
16313  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
16314  IATrackSN = InactiveTrackElement.LocationName;
16315  }
16316  if(ActiveTrackFoundFlag)
16317  {
16318  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
16319  ATrackSN = ActiveTrackElement.LocationName;
16320  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
16321  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
16322  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
16323  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
16324  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
16325  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
16326  {
16327  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
16328  }
16329  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
16330  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
16331  {
16332  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
16333  }
16334  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
16335  {
16336  TwoTrack = true;
16337  }
16338  Length01Str = AnsiString(ActiveTrackElement.Length01);
16339  if(Length01Str == "-1")
16340  {
16341  Length01Str = "Not Set";
16342  }
16343  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
16344  if(SpeedLimit01Str == "-1")
16345  {
16346  SpeedLimit01Str = "Not Set";
16347  }
16348  if(TwoTrack)
16349  {
16350  Length23Str = AnsiString(ActiveTrackElement.Length23);
16351  if(Length23Str == "-1")
16352  {
16353  Length23Str = "Not Set"; // shouldn't be -1 but leave in
16354  }
16355  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
16356  if(SpeedLimit23Str == "-1")
16357  {
16358  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
16359  }
16360  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
16361  {
16362  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
16363  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
16364  }
16365  else if(ActiveTrackElement.TrackType == Points)
16366  {
16367  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
16368  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
16369  SpeedLimit23Str + " km/h";
16370  }
16371  else if(ActiveTrackElement.TrackType == Crossover)
16372  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
16373  {
16374  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
16375  {
16376  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
16377  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
16378  }
16379  else if(ActiveTrackElement.SpeedTag == 47)
16380  {
16381  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
16382  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
16383  }
16384  else if(ActiveTrackElement.SpeedTag == 45)
16385  {
16386  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
16387  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
16388  }
16389  else if(ActiveTrackElement.SpeedTag == 44)
16390  {
16391  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
16392  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
16393  }
16394  else if(ActiveTrackElement.SpeedTag == 16)
16395  {
16396  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
16397  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
16398  SpeedLimit23Str + " km/h";
16399  }
16400  }
16401  else // bridge
16402  {
16403  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
16404  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
16405  }
16406  }
16407  else
16408  {
16409  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
16410  }
16411  }
16412  if(ActiveTrackFoundFlag)
16413  {
16414  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
16415  // in case wish to resurrect this line for any reason
16416  ShowTrackFloatFlag = true;
16417  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
16418  {
16419  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
16420  }
16421  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
16422  {
16423  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
16424  }
16425 
16426  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
16427  {
16428  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
16429  }
16430 
16431  else // no timetable or location name, just track
16432  {
16433  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
16434  }
16435  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
16436  {
16437  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
16438  {
16439  SigAspectString = "\nThree-aspect signal";
16440  }
16441  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
16442  {
16443  SigAspectString = "\nTwo-aspect signal";
16444  }
16445  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
16446  {
16447  SigAspectString = "\nGround signal";
16448  }
16449  else
16450  {
16451  SigAspectString = "\nFour-aspect signal";
16452  }
16453  TrackFloat += SigAspectString;
16454  }
16455  } // if(ActiveFoundFlag)
16456  else if(InactiveTrackFoundFlag) // inactive element but no active element,
16457  // i.e. concourse or non-station name at a blank element
16458  {
16459  ShowTrackFloatFlag = true;
16460  if(InactiveTrackElement.TrackType != Parapet)
16461  {
16462  if(IATrackSN == "")
16463  {
16464  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
16465  }
16466  else
16467  {
16468  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
16469  }
16470  }
16471  else // it is a parapet, just show the ID
16472  {
16473  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
16474  }
16475  }
16476  }
16477 // end of TrackFloat section
16478 
16479  bool OAListBoxFloatRequired = false; // identifies which window needs the float
16480  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
16481  // if caption is 'Hide' label is required
16482  {
16483  bool FoundFlag;
16484  AnsiString FormatOneDPStr = "####0.0";
16485  AnsiString FormatNoDPStr = "#######0";
16486 // AnsiString Format5DPStr = "####0.00000"; //temporary
16487  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
16488  AnsiString SpecialStr = "";
16489  if(OperatorActionPanel->Visible) // added at v2.6.2 to show floating window for trains in actions due list
16490  {
16491  if(OAListBox->MouseInClient && !OperatorActionPanel->MouseInClient && OAListBoxRightMouseButtonDown)
16492  {
16493  int X = OAListBox->ScreenToClient(MousePoint).x;
16494  int Y = OAListBox->ScreenToClient(MousePoint).y;
16495  int TrainID = -1, ContinuationPos = -1;
16496  if(GetTrainIDOrContinuationPosition(1, X, Y, TrainID, ContinuationPos))
16497  {
16498  OAListBoxFloatRequired = true;
16499  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
16500  {
16501  ShowTrainStatusFloatFlag = true;
16502  }
16503  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16504  {
16505  ShowTrainTTFloatFlag = true;
16506  }
16507  if((TrainID > -1) && (ShowTrainStatusFloatFlag || ShowTrainTTFloatFlag))
16508  {
16509  TTrain Train = TrainController->TrainVectorAtIdent(53, TrainID);
16510  TrainStatusFloat = GetTrainStatusFloat(0, TrainID, FormatNoDPStr, SpecialStr);
16511  TrainTTFloat = Train.FloatingTimetableString(1, Train.ActionVectorEntryPtr);
16512  }
16513  else if(ContinuationPos > -1)
16514  {
16515  GetTrainFloatingInfoFromContinuation(0, ContinuationPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
16516  }
16517  }
16518  }
16519  }
16520  if(!OAListBoxFloatRequired) // condition added at v2.6.2 so only one floating window can show
16521  {
16522  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
16523  if(FoundFlag && !MouseOverOAPanel) // MouseOverOAPanel added at v2.7.0 to prevent trains showimng behind OA panel
16524  {
16525  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
16526  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
16527  {
16528  int TrainID = Track->TrackElementAt(452, VecPos).TrainIDOnElement;
16529  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
16530  {
16531  ShowTrainStatusFloatFlag = true;
16532  TrainStatusFloat = GetTrainStatusFloat(1, TrainID, FormatNoDPStr, SpecialStr);
16533  }
16534  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16535  {
16536  ShowTrainTTFloatFlag = true;
16537  TTrain Train = TrainController->TrainVectorAtIdent(54, TrainID);
16538  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
16539  }
16540  }
16541 
16542  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
16543  // always give train information if a train present, but if not & either of train status or timetable info
16544  // selected then give next expected train to enter, or 'No trains expected'
16545  {
16546  TrainStatusFloat = "No trains expected";
16547  TrainTTFloat = "No timetable";
16548  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
16549  {
16550  ShowTrainStatusFloatFlag = true;
16551  }
16552  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16553  {
16554  ShowTrainTTFloatFlag = true;
16555  }
16557  {
16558  GetTrainFloatingInfoFromContinuation(1, VecPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
16559  }
16560  }
16561  }
16562  }
16563  }
16564 // end of TrainFloat section
16565  AnsiString Caption;
16566 
16567  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16568  {
16569  FloatingPanel->Visible = false;
16570  Utilities->CallLogPop(1485);
16571  return; // return with label invisible
16572  }
16573  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16574  {
16575  Caption = TrackFloat;
16576  }
16577  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16578  {
16579  Caption = TrainStatusFloat;
16580  }
16581  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
16582  {
16583  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
16584  }
16585  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16586  {
16587  if(TrainStatusFloat == "No trains expected")
16588  {
16589  Caption = TrainStatusFloat;
16590  }
16591  else
16592  {
16593  Caption = TrainTTFloat;
16594  }
16595  }
16596  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16597  {
16598  if(TrainStatusFloat == "No trains expected")
16599  {
16600  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
16601  }
16602  else
16603  {
16604  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
16605  }
16606  }
16607  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16608  {
16609  if(TrainStatusFloat == "No trains expected")
16610  {
16611  Caption = TrainStatusFloat;
16612  }
16613  else
16614  {
16615  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
16616  }
16617  }
16618  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
16619  {
16620  if(TrainStatusFloat == "No trains expected")
16621  {
16622  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
16623  }
16624  else
16625  {
16626  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
16627  }
16628  }
16629  int WindowOffsetLeft = 16;
16630  int WindowOffsetRight = 16;
16631  if(OAListBoxFloatRequired)
16632  {
16633  WindowOffsetLeft = 32;
16634  WindowOffsetRight = 64;
16635  }
16636  FloatingLabel->Caption = Caption; // set this here so dimensions correct in calculations, moved from below at v2.7.0
16637  FloatingPanel->Visible = true; // need this or dimensions still not valid, moved from below at v2.7.0
16638 
16639  int Left = ScreenX + MainScreen->Left + WindowOffsetRight; // so lhs of window is WindowOffset to the right of the mouse pos
16640 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
16641 // offset 32 to the right and 95 down from the interface form
16642  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
16643  {
16644  Left = ScreenX - FloatingPanel->Width + 32 - WindowOffsetLeft;
16645  }
16646 // so rhs of window is 32 - WindowOffset to the left of the mouse pos (+32 would be at mouse pos)
16647  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
16648 
16649  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
16650  {
16651  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
16652  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
16653  // lose something then it's best to be from the bottom
16654  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
16655  // obscure the window
16656  {
16657  Top = 30;
16658  }
16659  }
16660 /* if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top)) //dropped at v2.7.0 as causes more flickler than allowing window to move with mouse
16661  {
16662  FloatingPanel->Visible = false; // so doesn't flicker when reposition
16663  FloatingPanel->Left = Left;
16664  FloatingPanel->Top = Top;
16665  Utilities->CallLogPop(1917);
16666  return;
16667  }
16668 */
16669 
16670  FloatingPanel->Left = Left; // new at v2.7.0 in place of above
16671  FloatingPanel->Top = Top;
16672 
16673 // FloatingLabel->Caption = Caption; moved up at v2.7.0
16674 // FloatingPanel->Visible = true; // moved up at v2.7.0
16675  FloatingPanel->BringToFront();
16676  Utilities->CallLogPop(746);
16677 }
16678 
16679 // ---------------------------------------------------------------------------
16680 
16681 void TInterface::GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat,
16682  AnsiString &TrainTTFloat)
16683 {
16684  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainFloatingInfoFromContinuation");
16686  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
16687  float EntrySpeed;
16689  {
16690  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
16691  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
16692  {
16693  CTEIt++;
16694  }
16696  {
16697  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
16698  AnsiString ServiceReferenceInfo = "";
16699  // Repeat information
16700  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
16701  {
16702  if(CTEIt->second.RepeatNumber == 0)
16703  {
16704  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
16705  {
16706  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
16707  }
16708  else
16709  {
16710  ServiceReferenceInfo = "\nFirst service";
16711  }
16712  }
16713  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
16714  {
16715  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
16716  }
16717  else
16718  {
16719  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " + TTDEPtr->ServiceReference;
16720  }
16721  }
16722  else
16723  {
16724  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
16725  {
16726  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
16727  }
16728  }
16729  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
16730  {
16731  SpecialStr = "\nTrain under signaller control";
16732  EntrySpeed = TTDEPtr->SignallerSpeed;
16733  if(EntrySpeed > LineSpeedLimit)
16734  {
16735  EntrySpeed = LineSpeedLimit;
16736  }
16737  }
16738  else
16739  {
16740  EntrySpeed = TTDEPtr->StartSpeed;
16741  if(EntrySpeed > LineSpeedLimit)
16742  {
16743  EntrySpeed = LineSpeedLimit;
16744  }
16745  }
16746  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
16747  {
16748  TDateTime TempTime = CTEIt->first;
16749 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
16750  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
16751  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " + Utilities->Format96HHMM(TempTime);
16752  }
16753  else
16754  {
16755  TDateTime TempTime = CTEIt->first;
16756 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
16757  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
16758  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " + Utilities->Format96HHMM(TempTime);
16759  }
16760  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
16761  {
16762  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
16763  {
16764  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber, CTEIt->second.IncrementalMinutes,
16765  CTEIt->second.IncrementalDigits);
16766  }
16767  }
16768  }
16769  }
16770  Utilities->CallLogPop(2262);
16771 }
16772 
16773 // ---------------------------------------------------------------------------
16774 
16775 AnsiString TInterface::GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
16776 // new at v2.6.2 to make it easier to show also from actions due panel
16777 {
16778  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainStatusFloat");
16779  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
16780  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
16781  AnsiString FormatOneDPStr = "####0.0", MaxBrakeStr = "", MaxSpeedStr = "", TrainStatusFloat;
16782 
16783  double CurrSpeed;
16784  TTrain Train = TrainController->TrainVectorAtIdent(1, TrainID);
16785  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
16786  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
16787  if(Train.BeingCalledOn)
16788  {
16789  MaxSpeedStr = "30";
16790  }
16791  else
16792  {
16793  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
16794  }
16795  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
16796  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
16797  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
16798  TDateTime TimeLeft;
16799  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
16800  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
16801  HeadCode = Train.HeadCode;
16802  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
16803  {
16804  if(Train.RepeatNumber == 0)
16805  {
16806  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
16807  {
16808  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
16809  }
16810  else
16811  {
16812  ServiceReferenceInfo = "\nFirst service";
16813  }
16814  }
16815  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
16816  {
16817  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
16818  }
16819  else
16820  {
16821  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " + Train.TrainDataEntryPtr->ServiceReference;
16822  }
16823  }
16824  else
16825  {
16826  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
16827  {
16828  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
16829  }
16830  }
16831  if(Train.Stopped())
16832  {
16833  if(Train.SignallerStopped)
16834  {
16835  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
16836  }
16837  if(Train.NotInService)
16838  {
16839  Status = "Not in service"; // not used so far but leave it in
16840  }
16841  if(Train.StoppedAtBuffers)
16842  {
16843  Status = "Stopped at buffers";
16844  }
16845  if(Train.StoppedAtSignal)
16846  {
16847  Status = "Stopped at signal";
16848  }
16849  if(Train.StoppedForTrainInFront)
16850  {
16851  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
16852  }
16853  if(Train.StoppedAtLocation)
16854  {
16855  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
16856  }
16857  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
16858  {
16859  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
16860  }
16861  if(Train.StoppedWithoutPower)
16862  {
16863  if(Train.TrainFailed)
16864  {
16865  Status = "Stopped without power - train failed";
16866  }
16867  else
16868  {
16869  Status = "Stopped without power";
16870  }
16871  }
16872  if(Train.StoppedAfterSPAD)
16873  {
16874  Status = "Stopped - signal passed at danger";
16875  }
16876  if(Train.Derailed)
16877  {
16878  Status = "Derailed";
16879  }
16880  if(Train.Crashed)
16881  {
16882  Status = "Crashed";
16883  }
16884  CurrSpeed = 0;
16885  }
16886  else if(Train.OneLengthAccelDecel)
16887  {
16888  if(Train.FirstHalfMove)
16889  {
16890  Status = "Accelerating"; // just display a linear speed rise over half length
16891  BrakePCRate = 0; // reset to proper value during braking
16892  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
16893  }
16894  else
16895  {
16896  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
16897  if(BrakePCRate < 55)
16898  {
16899  Status = "Light braking";
16900  }
16901  else if(BrakePCRate < 90)
16902  {
16903  Status = "Heavy braking";
16904  }
16905  else
16906  {
16907  Status = "Emergency braking";
16908  }
16909  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
16910  }
16911  }
16912  else if(Train.BrakeRate > 0.01)
16913  {
16914  if(BrakePCRate < 55)
16915  {
16916  Status = "Light braking";
16917  }
16918  else if(BrakePCRate < 90)
16919  {
16920  Status = "Heavy braking";
16921  }
16922  else
16923  {
16924  Status = "Emergency braking";
16925  }
16926  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
16927  }
16928 
16929  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
16930  {
16931  Status = "Accelerating"; // just display a linear speed rise over half length
16932  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
16933  }
16934 
16935  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
16936  {
16937  Status = "Accelerating";
16938  CurrSpeed = Train.ExitSpeedHalf +
16939  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
16940  }
16941 
16942  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
16943  {
16944  if(Train.PowerAtRail < 1)
16945  {
16946  if(Train.TrainFailed)
16947  {
16948  Status = "Coasting - train failed";
16949  }
16950  else
16951  {
16952  Status = "Coasting - no power";
16953  }
16954  CurrSpeed = Train.ExitSpeedFull;
16955  }
16956  else
16957  {
16958  Status = "Constant speed";
16959  CurrSpeed = Train.ExitSpeedFull;
16960  }
16961  }
16962 
16963  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
16964  {
16965  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
16966  {
16967  if(Train.TrainFailed)
16968  {
16969  Status = "Coasting - train failed";
16970  }
16971  else
16972  {
16973  Status = "Coasting - no power";
16974  }
16975  CurrSpeed = Train.ExitSpeedHalf;
16976  }
16977  else
16978  {
16979  Status = "Constant speed";
16980  CurrSpeed = Train.ExitSpeedHalf;
16981  }
16982  }
16983  if(Train.TimetableFinished)
16984  {
16985  if(Train.TrainMode == Signaller)
16986  {
16987  NextStopStr = "At signaller's discretion";
16988  }
16989  else
16990  {
16991  NextStopStr = "None";
16992  }
16993  }
16994  else
16995  {
16996  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
16997  }
16998  if(Train.TrainMode == Signaller)
16999  {
17000  SpecialStr = "Train under signaller control" + AnsiString('\n');
17001  }
17002  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
17003  {
17004  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
17005  }
17006  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
17007  if(RemTimeHalf < 0)
17008  {
17009  RemTimeHalf = 0;
17010  }
17011  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
17012  if(RemTimeFull < 0)
17013  {
17014  RemTimeFull = 0;
17015  }
17016  if(RemTimeHalf > 0)
17017  {
17018  TimeLeft = RemTimeHalf;
17019  }
17020  else
17021  {
17022  TimeLeft = RemTimeFull;
17023  }
17024  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
17025  if(Train.Stopped())
17026  {
17027  TimeToNextMovementStr = "";
17028  }
17029  if(Train.Stopped())
17030  {
17031  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
17032  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + '\n' + "Next: " +
17033  NextStopStr;
17034  }
17035  else
17036  {
17037  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " + MaxSpeedStr +
17038  "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr + Status + ": " +
17039  CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
17040  }
17041  Utilities->CallLogPop(2263);
17042  return(TrainStatusFloat);
17043 }
17044 
17045 // ---------------------------------------------------------------------------
17046 
17047 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
17048 // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
17049 // Gap flashing is cancelled on any mousedown event
17050 
17051 {
17052  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
17053 // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
17055  {
17056  if(WarningFlash)
17057  {
17058  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
17060  }
17061  else
17062  {
17063  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
17065  }
17066  }
17068  {
17069  if(WarningFlash)
17070  {
17075  Display->Update();
17076  }
17077  else
17078  {
17083  Display->Update();
17084  }
17085  }
17086 // deal with gap setting - added at v2.6.1 to make location easier
17088  {
17090  }
17092  {
17093  Display->Ellipse(2, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB0G0R5);
17094  }
17096  {
17098  }
17100  {
17101  Display->Ellipse(3, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB5G5R5);
17102  }
17103 // deal with other flashing graphics
17105  {
17106  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
17107  {
17108  // cancel if train is moving & arrives on any part of flashing route
17110  {
17111  Track->RouteFlashFlag = false;
17113  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
17114  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
17115  Utilities->CallLogPop(75);
17116  return;
17117  }
17118  InfoPanel->Visible = true;
17119  if(Level2OperMode == PreStart)
17120  {
17121  InfoPanel->Caption = "PRE-START: Route setting in progress";
17122  }
17123  else
17124  {
17125  InfoPanel->Caption = "OPERATING: Route setting in progress";
17126  }
17127  if(WarningFlash)
17128  {
17130  }
17131  else
17132  {
17134  }
17135  }
17136  else
17137  {
17138 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
17139 // stop clock while converting route as can take several seconds
17140  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17142  if(PreferredRouteFlag)
17143  {
17145  }
17146  else
17147  {
17149  }
17150  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
17151  TrainController->BaseTime = TDateTime::CurrentDateTime();
17153  Track->RouteFlashFlag = false;
17155  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
17156  }
17157  }
17158  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
17159  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
17160  // no need to call Clearand... as that is called when revert to normal mode
17161  {
17162  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
17163  {
17164  Track->RouteFlashFlag = false;
17165  if(PreferredRouteFlag)
17166  {
17168  }
17169  else
17170  {
17172  }
17173  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
17174  }
17175  }
17177  {
17178  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
17179  {
17180  // cancel if train is present on or enters a flashing point, either selected or diverging
17182  {
17184  Track->PointFlashFlag = false;
17186  Utilities->CallLogPop(76);
17187  return;
17188  }
17190  {
17192  Track->PointFlashFlag = false;
17194  Utilities->CallLogPop(77);
17195  return;
17196  }
17197  if(WarningFlash)
17198  {
17201  }
17202  else
17203  {
17205  }
17206  }
17207  else
17208  {
17213  {
17217  }
17219  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
17220  Track->PointFlashFlag = false;
17222  }
17223  }
17225  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
17226  {
17227  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
17228  {
17232  {
17235  }
17236  Track->PointFlashFlag = false;
17238  }
17239  }
17240 // deal with changing level crossings
17241  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
17242  {
17243  int H;
17244  int V;
17245 
17246  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
17247  {
17248  bool Manual = false;
17249  if(Track->ChangingLCVector.at(x).TypeOfRoute == 2) // manual
17250  {
17251  Manual = true;
17252  }
17253  H = Track->ChangingLCVector.at(x).HLoc;
17254  V = Track->ChangingLCVector.at(x).VLoc;
17255  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
17256  // still flashing
17257  {
17258  if(WarningFlash)
17259  {
17260  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
17261  {
17262  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
17263 // always plots red when raising
17264  }
17265  else
17266  {
17267  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
17268  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
17269  }
17270  }
17271  else
17272  {
17273  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
17274  Track->ChangingLCVector.at(x).TypeOfRoute, Display);
17275  }
17276  }
17277  else
17278  // flashing period finished
17279  {
17280  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
17281  {
17282  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
17283 // always plot red when fully raised
17284  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
17285  // attributes set to 2 when changing state, now reset to 0, no other actions needed
17286  }
17287  else
17288  // barriers lowering
17289  {
17290  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
17291  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
17292  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
17293  bool FoundFlag;
17294  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
17295  if(!FoundFlag)
17296  {
17297  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
17298  }
17299  int RouteNumber;
17300  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
17301  // don't need returned value of RouteType
17302  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
17303  {
17304  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
17305  }
17306  }
17307  }
17308  }
17309  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
17310  {
17311  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector if lowering, reset the start timer (to time the barrier down period)
17312  // and for either raising or lowering erase the object from the ChangingLCVector
17313  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
17314  {
17315  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
17316  {
17317  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
17318  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
17319  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
17320  }
17321  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
17322  }
17323  }
17324  }
17325  Utilities->CallLogPop(747);
17326 }
17327 
17328 // ---------------------------------------------------------------------------
17329 
17331 // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
17332 {
17333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
17334 
17335 // set save railway buttons
17336  bool SaveRailwayButtonsFlag = true;
17337 
17338  SaveRailwayTBPButton->Visible = true;
17339  SaveRailwayPDPButton->Visible = true;
17340  SaveSessionButton->Visible = true;
17341  if(Level1Mode == OperMode)
17342  {
17344  {
17345  SaveRailwayButtonsFlag = false;
17346  }
17347  // set PresetAutoSigRoutesButton enabled or not
17348  // enable if PreStart & no routes set
17349  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()))
17350  {
17351  PresetAutoSigRoutesButton->Enabled = true;
17352  }
17353  else
17354  {
17355  PresetAutoSigRoutesButton->Enabled = false;
17356  }
17357  }
17358  else
17359  {
17361  && Track->UserGraphicVector.empty()))
17362  {
17363  SaveRailwayButtonsFlag = false;
17364  }
17365  else if(SavedFileName != "")
17366  {
17367  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
17368  {
17369  if(!(Track->IsReadyForOperation(false)))
17370  {
17371  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
17372  }
17373  }
17374  }
17375  }
17376  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
17377  {
17378  SaveRailwayBaseModeButton->Visible = true;
17379  }
17380  else
17381  {
17382  SaveRailwayBaseModeButton->Visible = false;
17383  }
17384  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
17385  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
17386  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
17387  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
17388 
17389 // set formatted timetable menu item
17390  if(TimetableTitle == "")
17391  {
17392  ExportTTMenuItem->Enabled = false;
17393  }
17394  else
17395  {
17396  ExportTTMenuItem->Enabled = true;
17397  }
17398 // set info menu items
17400  {
17401  FloatingInfoMenu->Enabled = false;
17402  TrackInfoMenuItem->Enabled = false;
17403  TrainInfoMenuItem->Enabled = false;
17404  }
17405  else
17406  {
17407  FloatingInfoMenu->Enabled = true;
17408  TrackInfoMenuItem->Enabled = true;
17409  if(Level1Mode == OperMode)
17410  {
17411  TrainInfoMenuItem->Enabled = true;
17412  }
17413  else
17414  {
17415  TrainInfoMenuItem->Enabled = false;
17416  }
17417  }
17418 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
17419 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
17420 // there has been a legitimate change of state since the last access
17421 
17422  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
17423  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
17424 
17425  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
17426  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
17427  AnsiString OperatingPanelLabelCaptionStr = "Operation";
17428  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
17429 
17430  if(!Display->ZoomOutFlag)
17431  {
17432  // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
17434  {
17435  ScreenLeftFlag = false; // 60 - 30
17436  }
17438  {
17439  ScreenRightFlag = false; // 60 - (60 - 30)
17440  }
17442  {
17443  ScreenUpFlag = false; // 36 - 18
17444  }
17446  {
17447  ScreenDownFlag = false; // 36 - (36 - 18)
17448  }
17449  }
17450  else
17451  {
17452  // prevent if less than a quarter of a screen visible (width = 240, height = 144)
17454  {
17455  ScreenLeftFlag = false; // 240 - 60
17456  }
17458  {
17459  ScreenRightFlag = false; // 240 - (240 - 60)
17460  }
17462  {
17463  ScreenUpFlag = false; // 144 - 36
17464  }
17466  {
17467  ScreenDownFlag = false; // 144 - (144 - 36)
17468  }
17469  }
17471  {
17472  ZoomFlag = false;
17473  HomeFlag = false;
17474  NewHomeFlag = false;
17475  ScreenLeftFlag = false;
17476  ScreenRightFlag = false;
17477  ScreenUpFlag = false;
17478  ScreenDownFlag = false;
17479  }
17480  if(Display->ZoomOutFlag)
17481  {
17482 // NewHomeFlag = false;
17483  TrackBuildPanelEnabledFlag = false;
17484  TrackBuildPanelLabelCaptionStr = "Disabled";
17485  PrefDirPanelEnabledFlag = false;
17486  PrefDirPanelLabelCaptionStr = "Disabled";
17487  OperatingPanelEnabledFlag = false;
17488  OperatingPanelLabelCaptionStr = "Disabled";
17489  TimetablePanelEnabledFlag = false;
17490  TimetablePanelLabelCaptionStr = "Disabled";
17491  }
17492  if(Level1Mode == OperMode)
17493  {
17494  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true)
17495  // TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
17496  {
17497  MTBFEditBox->Enabled = false;
17498  OperatingPanelEnabledFlag = false;
17499  OperatingPanelLabelCaptionStr = "Disabled";
17500  ZoomFlag = false;
17501  HomeFlag = false;
17502  NewHomeFlag = false;
17503  ScreenLeftFlag = false;
17504  ScreenRightFlag = false;
17505  ScreenUpFlag = false;
17506  ScreenDownFlag = false;
17507  SaveOperatingImageMenuItem->Enabled = false;
17508  }
17509  else
17510  {
17511  MTBFEditBox->Enabled = true;
17512  SaveOperatingImageMenuItem->Enabled = true;
17513  }
17514  }
17515  if(LocationNameTextBox->Visible)
17516  {
17517  ZoomFlag = false;
17518  HomeFlag = false;
17519  NewHomeFlag = false;
17520  ScreenLeftFlag = false;
17521  ScreenRightFlag = false;
17522  ScreenUpFlag = false;
17523  ScreenDownFlag = false;
17524  }
17525  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
17526  {
17527  ZoomFlag = false;
17528  HomeFlag = false;
17529  NewHomeFlag = false;
17530  ScreenLeftFlag = false;
17531  ScreenRightFlag = false;
17532  ScreenUpFlag = false;
17533  ScreenDownFlag = false;
17534  }
17535  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
17536  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
17537  {
17538  ZoomFlag = false;
17539  HomeFlag = false;
17540  NewHomeFlag = false;
17541  ScreenLeftFlag = false;
17542  ScreenRightFlag = false;
17543  ScreenUpFlag = false;
17544  ScreenDownFlag = false;
17545  }
17548  {
17549  ZoomFlag = false;
17550  }
17551  if(ZoomFlag)
17552  {
17553  ZoomButton->Enabled = true;
17554  }
17555  else
17556  {
17557  ZoomButton->Enabled = false;
17558  }
17559  if(HomeFlag)
17560  {
17561  HomeButton->Enabled = true;
17562  }
17563  else
17564  {
17565  HomeButton->Enabled = false;
17566  }
17567  if(NewHomeFlag)
17568  {
17569  NewHomeButton->Enabled = true;
17570  }
17571  else
17572  {
17573  NewHomeButton->Enabled = false;
17574  }
17575  if(ScreenLeftFlag)
17576  {
17577  ScreenLeftButton->Enabled = true;
17578  }
17579  else
17580  {
17581  ScreenLeftButton->Enabled = false;
17582  }
17583  if(ScreenRightFlag)
17584  {
17585  ScreenRightButton->Enabled = true;
17586  }
17587  else
17588  {
17589  ScreenRightButton->Enabled = false;
17590  }
17591  if(ScreenUpFlag)
17592  {
17593  ScreenUpButton->Enabled = true;
17594  }
17595  else
17596  {
17597  ScreenUpButton->Enabled = false;
17598  }
17599  if(ScreenDownFlag)
17600  {
17601  ScreenDownButton->Enabled = true;
17602  }
17603  else
17604  {
17605  ScreenDownButton->Enabled = false;
17606  }
17607  if(OperatingPanelEnabledFlag)
17608  {
17609  OperatingPanel->Enabled = true;
17610  }
17611  else
17612  {
17613  OperatingPanel->Enabled = false;
17614  }
17615  if(TrackBuildPanelEnabledFlag)
17616  {
17617  TrackBuildPanel->Enabled = true;
17618  }
17619  else
17620  {
17621  TrackBuildPanel->Enabled = false;
17622  }
17623  if(PrefDirPanelEnabledFlag)
17624  {
17625  PrefDirPanel->Enabled = true;
17626  }
17627  else
17628  {
17629  PrefDirPanel->Enabled = false;
17630  }
17631  if(TimetablePanelEnabledFlag)
17632  {
17633  TimetablePanel->Enabled = true;
17634  }
17635  else
17636  {
17637  TimetablePanel->Enabled = false;
17638  }
17639  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
17640  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
17641  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
17642  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
17643 
17644 // check if any CallingOnFlags set & set button accordingly
17645  if(Display->ZoomOutFlag)
17646  {
17647  CallingOnButton->Enabled = false;
17648  CallingOnButton->Down = false;
17649  }
17650  else
17651  {
17652  if(Level2OperMode == Operating)
17653  {
17654  bool CallOnValid = false;
17655  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
17656  {
17658  {
17659  CallingOnButton->Enabled = true;
17660  CallOnValid = true;
17661  }
17662  }
17663  if(!CallOnValid)
17664  {
17665  CallingOnButton->Enabled = false;
17666  CallingOnButton->Down = false;
17667  }
17668  }
17669  else
17670  {
17671  CallingOnButton->Enabled = false;
17672  CallingOnButton->Down = false;
17673  }
17674  }
17675  Utilities->CallLogPop(970);
17676 }
17677 
17678 // ---------------------------------------------------------------------------
17679 
17680 void TInterface::ErrorLog(int Caller, AnsiString Message)
17681 {
17682 // create an error file for diagnostic purposes called on detection of a runtime error
17683 
17684 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
17685 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
17686 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
17687 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
17688 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
17689 // depending on the time taken to press Exit.
17690 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
17691 
17692  if(ErrorLogCalledFlag)
17693  {
17694  return;
17695  }
17696  ErrorLogCalledFlag = true;
17697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
17698  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
17699  SaveErrorFile();
17700  if((TempTTFileName != "") && FileExists(TempTTFileName))
17701  {
17702  DeleteFile(TempTTFileName);
17703  }
17704  Display->GetImage()->Visible = false;
17705  PerformancePanel->Visible = false;
17706  OperatorActionPanel->Visible = false; // new v2.2.0
17707  TrackBuildPanel->Visible = false;
17708  TrackElementPanel->Visible = false;
17709  LocationNameTextBox->Visible = false;
17710  TextBox->Visible = false;
17711  TrackLengthPanel->Visible = false;
17712  InfoPanel->Visible = false;
17713  PrefDirPanel->Visible = false;
17714  TimetablePanel->Visible = false;
17715  TimetableEditPanel->Visible = false;
17716  TrainController->TTEditPanelVisible = false; // added at v2.6.0 for two location message
17717  OperatingPanel->Visible = false;
17718  FloatingPanel->Visible = false;
17719  ModeMenu->Enabled = false;
17720  SigImagePanel->Visible = false; // new at v2.3.0
17721  FileMenu->Enabled = false;
17722  EditMenu->Enabled = false;
17723  FloatingInfoMenu->Enabled = false;
17724  HelpMenu->Enabled = false;
17725 // SaveHeaderMenu1->Enabled = false;
17726  ScreenLeftButton->Visible = false;
17727  ScreenRightButton->Visible = false;
17728  ScreenUpButton->Visible = false;
17729  ScreenDownButton->Visible = false;
17730  HomeButton->Visible = false;
17731  NewHomeButton->Visible = false;
17732  ZoomButton->Visible = false;
17733  PrefDirKey->Visible = false;
17734  DistanceKey->Visible = false;
17735  RecoverClipboardMessageSent = true; // to stop paste message being given if recover clipboard error
17736  OutputLog1->Caption = "";
17737  OutputLog2->Caption = "";
17738  OutputLog3->Caption = "";
17739  OutputLog4->Caption = "";
17740  OutputLog5->Caption = "";
17741  OutputLog6->Caption = "";
17742  OutputLog7->Caption = "";
17743  OutputLog8->Caption = "";
17744  OutputLog9->Caption = "";
17745  OutputLog10->Caption = "";
17746  if(Caller == 113)
17747  {
17748  ErrorMessageStoreImage->Visible = true;
17749  }
17750  else
17751  {
17752  ErrorMessage->Visible = true;
17753  }
17754  ErrorButton->Visible = true;
17755  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
17756 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
17757 // is to close the program when the exit button is pressed
17758 }
17759 
17760 // ---------------------------------------------------------------------------
17761 
17763 // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
17764 {
17765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
17766  if(FloatingPanel->Visible == false)
17767  {
17768  Utilities->CallLogPop(1205);
17769  return(false);
17770  }
17771 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
17772  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
17773  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
17774  {
17775  Utilities->CallLogPop(1206);
17776  return(false);
17777  }
17778  else
17779  {
17780  Utilities->CallLogPop(1207);
17781  return(true);
17782  }
17783 }
17784 // ---------------------------------------------------------------------------
17785 
17786 void TInterface::SetCaption(int Caller)
17787 {
17788 /*
17789  NamedRailway; RlyFile; NamedTimetable
17790  n x x "New railway under development";
17791  y n x RailwayTitle + ": under development";
17792  y y n RailwayTitle + ": no timetable loaded";
17793  y y y RailwayTitle + ", " + TimetableTitle;
17794 */
17795 
17796  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
17797  if(RailwayTitle == "")
17798  {
17799  Caption = "Railway: New railway under development";
17800  }
17801  else if(!RlyFile)
17802  {
17803  Caption = "Railway: " + RailwayTitle + " under development";
17804  }
17805 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
17806  else if(TimetableTitle == "")
17807  {
17808  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
17809  }
17810  else
17811  {
17812  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
17813  }
17814  Utilities->CallLogPop(1208);
17815 }
17816 
17817 // ---------------------------------------------------------------------------
17818 
17819 void TInterface::ResetAll(int Caller)
17820 {
17821  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
17822  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
17824  Track->GapFlashRedPosition = -1;
17825  Track->GapFlashFlag = false;
17826  Track->RouteFlashFlag = false;
17827  Track->PointFlashFlag = false;
17829  AutoSigsFlag = false;
17830  PreventGapOffsetResetting = false;
17831 
17832  Utilities->Clock2Stopped = false;
17833  TTClockSpeed = 1;
17834  TTClockSpeedLabel->Caption = "x1";
17835  Track->SetTrackFinished(false);
17837  CurrentSpeedButton = 0; // not assigned yet
17839  StartX = 0;
17840  StartY = 0;
17841  mbLeftDown = false;
17843  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
17845  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
17847  WarningFlashCount = 0;
17848 
17849  Level1Mode = BaseMode;
17850  SetLevel1Mode(26);
17851  RouteMode = None;
17852  PreferredRoute = true; // default starting conditions
17853  ConsecSignalsRoute = true; // default starting conditions
17854  DevelopmentPanel->Visible = false;
17855 
17856  MainScreen->Canvas->CopyMode = cmSrcCopy;
17857  FloatingPanel->Visible = false;
17858  OverallDistance = 0;
17859  OverallSpeedLimit = -1;
17860  AllRoutes->RouteTruncateFlag = false;
17861  CallingOnButton->Down = false;
17862  Display->ZoomOutFlag = false;
17863  ScreenGridFlag = false;
17864  InfoCaptionStore = "";
17865  ErrorLogCalledFlag = false;
17866  ErrorMessage->Visible = false;
17867  ErrorMessageStoreImage->Visible = false;
17868  TempCursorSet = false;
17869  TempCursor = TCursor(-2); // Arrow
17870  WholeRailwayMoving = false; // new at v2.1.0
17871 
17872  TrainController->TTClockTime = TDateTime(0); // default setting
17873  TTClockAdjPanel->Visible = false;
17875  ConflictPanel->Visible = false;
17876  SelectedTrainID = -1;
17877  SetTrackBuildImages(11);
17878 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
17879 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
17880 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
17881  Track->CalcHLocMinEtc(8);
17882  FileChangedFlag = false;
17883  RlyFile = false;
17884  SaveSessionFlag = false;
17885  LoadSessionFlag = false;
17886  SelectionValid = false;
17887  TimetableChangedFlag = false;
17888  SavedFileName = "";
17889  RailwayTitle = "";
17890  TimetableTitle = "";
17891  SetCaption(1);
17892  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
17893  // added for Beta v0.2b
17894  CreateEditTTTitle = ""; // as above
17895  AllRoutes->NextRouteID = 0;
17896  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
17897  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
17898 
17899  TempFont->Style.Clear();
17900  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
17901  TempFont->Size = 10;
17902  TempFont->Color = clB0G0R0;
17903  TempFont->Charset = (TFontCharset)(0);
17904  MainScreen->Canvas->Font->Assign(TempFont);
17905  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
17906  PerformancePanel->Left = MainScreen->Left;
17907  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
17908  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
17909  ; // new v2.2.0
17910  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
17911  // ScreenLeftButton->Left = ScreenRightButton->Left;
17912  // ScreenUpButton->Left = ScreenRightButton->Left;
17913  // ScreenDownButton->Left = ScreenRightButton->Left;
17914  // HomeButton->Left = ScreenRightButton->Left;
17915  // NewHomeButton->Left = ScreenRightButton->Left;
17916  // ZoomButton->Left = ScreenRightButton->Left;
17917  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
17918  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width;
17919  ; // new v2.2.0
17920 
17921  delete TempFont;
17922  CtrlKey = false;
17923  ShiftKey = false;
17924  ClipboardChecked = false;
17925  Utilities->CallLogPop(1209);
17926 }
17927 
17928 // ---------------------------------------------------------------------------
17929 
17931 {
17932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
17933  if((Level1Mode == OperMode) || RlyFile)
17934  {
17935  TrackLinkedImage->Visible = false;
17936  TrackNotLinkedImage->Visible = false;
17937  GapsSetImage->Visible = false;
17938  GapsNotSetImage->Visible = false;
17939  LocationNamesSetImage->Visible = false;
17940  LocationNamesNotSetImage->Visible = false;
17941  Utilities->CallLogPop(1114);
17942  return;
17943  }
17944  else
17945  {
17946  if(!Track->NoActiveTrack(9))
17947  {
17948  if(Track->IsTrackFinished())
17949  {
17950  TrackLinkedImage->Visible = true;
17951  TrackNotLinkedImage->Visible = false;
17952  }
17953  else
17954  {
17955  TrackNotLinkedImage->Visible = true;
17956  TrackLinkedImage->Visible = false;
17957  }
17958  }
17959  else
17960  {
17961  TrackLinkedImage->Visible = false;
17962  TrackNotLinkedImage->Visible = false;
17963  }
17964  if(!Track->NoGaps(1))
17965  {
17966  if(Track->GapsUnset(6))
17967  {
17968  GapsNotSetImage->Visible = true;
17969  GapsSetImage->Visible = false;
17970  }
17971  else
17972  {
17973  GapsNotSetImage->Visible = false;
17974  GapsSetImage->Visible = true;
17975  }
17976  }
17977  else
17978  {
17979  GapsNotSetImage->Visible = false;
17980  GapsSetImage->Visible = false;
17981  }
17983  {
17984  if(Track->LocationsNotNamed(0))
17985  {
17986  LocationNamesSetImage->Visible = false;
17987  LocationNamesNotSetImage->Visible = true;
17988  }
17989  else
17990  {
17991  LocationNamesSetImage->Visible = true;
17992  LocationNamesNotSetImage->Visible = false;
17993  }
17994  }
17995  else
17996  {
17997  LocationNamesSetImage->Visible = false;
17998  LocationNamesNotSetImage->Visible = false;
17999  }
18000  }
18001  Utilities->CallLogPop(1113);
18002 }
18003 
18004 // ---------------------------------------------------------------------------
18005 
18006 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
18007 {
18008  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
18009  FileChangedFlag = true;
18010  if(NonPrefDirChangesMade)
18011  {
18012  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
18013  {
18014  RailwayTitle = "";
18015  TimetableTitle = "";
18016  SavedFileName = "";
18017  RlyFile = false;
18018  }
18019  TimetableTitle = ""; // should have been reset already during user mode change but include here also
18020  SetTrackBuildImages(15);
18021  }
18022  SetCaption(2);
18023  Utilities->CallLogPop(1210);
18024 }
18025 
18026 // ---------------------------------------------------------------------------
18027 
18028 void TInterface::SaveSession(int Caller)
18029 {
18030  // ExcessLCDownMins saved as string after ***Interface*** see below
18031  try
18032  {
18033  TrainController->LogEvent("SaveSession");
18034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
18035  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
18036  Screen->Cursor = TCursor(-11); // Hourglass;
18037  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
18038  // avoid characters in filename:= / \ : * ? " < > |
18039  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
18040  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
18041 // SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
18042 // "; " + TimetableTitle + ".ssn";
18043  SessionFileStr = LoadSessionDialog->InitialDir + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
18044  "; " + TimetableTitle + ".ssn";
18045  std::ofstream SessionFile(SessionFileStr.c_str());
18046  if(!(SessionFile.fail()))
18047  {
18048  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
18049 // added ExcessLC... at v2.2.0 as omitted earlier
18050  SaveInterface(0, SessionFile);
18051  // save track elements
18052  Utilities->SaveFileString(SessionFile, "***Track***");
18053  if(Track->UserGraphicVector.empty())
18054  {
18055  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
18056  }
18057  else
18058  {
18059  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
18060  }
18061  // save text elements
18062  Utilities->SaveFileString(SessionFile, "***Text***");
18063  TextHandler->SaveText(2, SessionFile);
18064  // save PrefDir elements
18065  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
18066  EveryPrefDir->SavePrefDirVector(2, SessionFile);
18067  if(!Track->UserGraphicVector.empty())
18068  {
18069  // save user graphics
18070  Track->SaveUserGraphics(2, SessionFile);
18071  }
18072  // save routes
18073  Utilities->SaveFileString(SessionFile, "***Routes***");
18074  AllRoutes->SaveRoutes(0, SessionFile);
18075  // save LockedRoutes
18076  Utilities->SaveFileString(SessionFile, "***Locked routes***");
18077  TrainController->SaveSessionLockedRoutes(0, SessionFile);
18078  // save ContinuationAutoSigEntries
18079  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
18081  // save BarriersDownVector
18082  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
18083  Track->SaveSessionBarriersDownVector(0, SessionFile);
18084  // save timetable
18085  Utilities->SaveFileString(SessionFile, "***Timetable***");
18086  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr)))
18087  {
18088  SessionFile.close();
18089  DeleteFile(SessionFileStr);
18090  Screen->Cursor = TCursor(-2); // Arrow;
18091  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
18092  Utilities->CallLogPop(1150);
18093  return;
18094  }
18095  // save TimetableClock
18096  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
18097  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
18098 
18099  // save trains
18100  Utilities->SaveFileString(SessionFile, "***Trains***");
18101  TrainController->SaveSessionTrains(0, SessionFile);
18102  // save performance file
18103  Utilities->SaveFileString(SessionFile, "***Performance file***");
18104  SavePerformanceFile(0, SessionFile);
18105  Utilities->SaveFileString(SessionFile, "***End of performance file***");
18106 
18107 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
18108  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
18111  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
18112  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
18113  {
18115  {
18118  }
18119  }
18120  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
18121  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
18122 // end of v2.4.0 addition
18123 
18124 // added at v2.7.0
18125  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
18126  Utilities->SaveFileString(SessionFile, "End of file at v2.7.0");
18127 // end of v2.7.0 addition
18128 
18129 // added at v2.9.1
18133  Utilities->SaveFileDouble(SessionFile, double(TrainController->TotEarlyExitMins));
18134  Utilities->SaveFileDouble(SessionFile, double(TrainController->TotLateExitMins));
18135  Utilities->SaveFileString(SessionFile, "End of file at v2.9.1"); //changed from '2.9.0' at v2.9.2
18136 // end of v2.9.1 additions
18137 
18138  SessionFile.close();
18139  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
18140  RailwayTitle + "; " + TimetableTitle + ".ssn");
18142 // to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
18143  }
18144  else
18145  {
18146  TrainController->StopTTClockMessage(5, "Session file failed to open - reason not known, session unable to be saved.");
18147  }
18149  Screen->Cursor = TCursor(-2); // Arrow
18150  Utilities->CallLogPop(1141);
18151  }
18152  catch(const Exception &e)
18153  {
18154  ErrorLog(40, e.Message);
18155  }
18156 }
18157 
18158 // ---------------------------------------------------------------------------
18159 
18160 void TInterface::LoadSession(int Caller)
18161 // always loads in 'Paused' or 'PreStart' mode
18162 {
18163 // remember to load the timetable clock
18164 // no routes in build
18165 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
18166 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
18167 // set RlyFile true
18168  try
18169  {
18170  TrainController->LogEvent("LoadSession");
18171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
18172  if(!ClearEverything(4))
18173  {
18174  Utilities->CallLogPop(1145);
18175  return;
18176  }
18177  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
18178  if(LoadSessionDialog->Execute())
18179  {
18180  if(LoadSessionDialog->InitialDir != TPath::GetDirectoryName(LoadSessionDialog->FileName)) // new at v2.6.0 to retain a new directory
18181  {
18182  LoadSessionDialog->InitialDir = TPath::GetDirectoryName(LoadSessionDialog->FileName);
18183  }
18184  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
18185  Screen->Cursor = TCursor(-11); // Hourglass;
18186  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
18187  // if(true)
18188  {
18189  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
18190  if(!(SessionFile.fail()))
18191  {
18192  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
18193  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
18194  AnsiString TempString = Utilities->LoadFileString(SessionFile);
18195 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
18196 
18197  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
18198  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
18199  // can't find it or no value for Excess LCDownMins, either way count as zero
18200  {
18202  }
18203  else
18204  {
18205  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
18206  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
18207  {
18209  }
18210  else
18211  {
18212  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
18213  }
18214  } // end of v2.2.0 * v2.4.0 additions
18215 
18216  LoadInterface(0, SessionFile);
18217  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
18218  int TempDisplayOffsetV = Display->DisplayOffsetV;
18219  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
18220  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
18221  bool GraphicsFollow = false;
18222  // load track elements
18223  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
18224  Track->LoadTrack(4, SessionFile, GraphicsFollow);
18225  // load text elements
18226  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
18227  TextHandler->LoadText(1, SessionFile);
18228  // load PrefDir elements
18229  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
18230  EveryPrefDir->LoadPrefDir(1, SessionFile);
18231  if(GraphicsFollow)
18232  {
18233  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
18234  }
18236  {
18237  SessionFile.close();
18238  Screen->Cursor = TCursor(-2); // Arrow;
18239  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
18240  Utilities->CallLogPop(1438);
18241  return;
18242  }
18243  // load routes
18244  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
18245  if(!AllRoutes->LoadRoutes(0, SessionFile))
18246  {
18247  SessionFile.close();
18248  Screen->Cursor = TCursor(-2); // Arrow;
18249  ShowMessage("Corruption in route section of the session file, session can't be loaded");
18250  Utilities->CallLogPop(1439);
18251  return;
18252  }
18253  // load LockedRoutes
18254  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
18255  TrainController->LoadSessionLockedRoutes(0, SessionFile);
18256  // load ContinuationAutoSigEntries
18257  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
18259  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
18260  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
18261  if(TempString == "***BarriersDownVector***")
18262  {
18263  Track->LoadBarriersDownVector(0, SessionFile);
18264  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
18265  }
18266  // load timetable (marker "***Timetable***" already loaded)
18267  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
18268  {
18269  SessionFile.close();
18270  Screen->Cursor = TCursor(-2); // Arrow;
18271  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
18272  Utilities->CallLogPop(1151);
18273  return;
18274  }
18275  // TimetableTitle should be loaded at this stage - check
18276  if(TimetableTitle == "")
18277  {
18278  SessionFile.close();
18279  Screen->Cursor = TCursor(-2); // Arrow;
18280  throw Exception("TimetableTitle null in LoadSession");
18281  }
18282  // load timetable clock
18283  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
18284  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
18285  // load trains
18286  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
18287  TrainController->LoadSessionTrains(0, SessionFile);
18288  // load performance file + populate the performance log
18289  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
18290  // first reset the performance file name and open it before reloading it
18291  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
18292  // avoid characters in filename:= / \ : * ? " < > |
18293  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
18294  TimetableTitle + ".txt";
18295  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
18296  if(Utilities->PerformanceFile.fail())
18297  {
18298  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
18299  " in the folder where the 'Railway.exe' program file resides");
18300  }
18301  // now reload the performance file
18302  LoadPerformanceFile(0, SessionFile);
18303  // addition at v2.4.0
18304  char TempChar;
18305  SessionFile.get(TempChar);
18306  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
18307  {
18308  SessionFile.get(TempChar);
18309  }
18310  if(SessionFile.eof()) // end of file
18311  {
18314  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
18315  // at v2.7.0 if find eof then don't need a value for ConsecSignalsRoute as that loaded same as PreferredRoute in interface
18316  }
18317  else //have v2.4.0 additions (train failures)
18318  {
18319  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
18320  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
18321  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
18322  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
18323  // now load any failed trains along with their OriginalPowerAtRail values
18324  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
18325  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
18326  double PowerDouble;
18327  while(ID != -1)
18328  {
18329  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
18332  ID = Utilities->LoadFileInt(SessionFile);
18333  }
18334  // added at v2.7.0 - need value for ConsecSignalsRoute but might have eof here with older sessions so first test for that
18335  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.4.0" discarded
18336  SessionFile.get(TempChar);
18337  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '0' or '1'
18338  {
18339  SessionFile.get(TempChar);
18340  }
18341  if(!SessionFile.eof()) // not end of file - have v2.7.0 addition
18342  {
18343  if((TempChar != '0') && (TempChar != '1'))
18344  {
18345  throw Exception("TempChar value = " + AnsiString(TempChar) + ", should be 0 or 1");
18346  }
18347  ConsecSignalsRoute = true;
18348  if(TempChar == '0')
18349  {
18350  ConsecSignalsRoute = false;
18351  }
18352  }
18353 
18354  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.7.0" discarded
18355  SessionFile.get(TempChar);
18356  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '0' or '1'
18357  {
18358  SessionFile.get(TempChar);
18359  }
18360  if(!SessionFile.eof()) // not end of file - have at v2.9.1 additions
18361  {
18362  //TempChar now contains the first digit of EarlyExits as an ASCII character, so get the rest up to CRLF
18363  AnsiString TempString = TempChar;
18364  SessionFile.get(TempChar);
18365  while((TempChar != '\n') && (TempChar != '\0'))
18366  {
18367  TempString = TempString + TempChar;
18368  SessionFile.get(TempChar);
18369  }
18370  TrainController->EarlyExits = TempString.ToInt();
18373  TrainController->TotEarlyExitMins = float(Utilities->LoadFileDouble(SessionFile));
18374  TrainController->TotLateExitMins = float(Utilities->LoadFileDouble(SessionFile));
18375  }
18376 
18377  SessionFile.close();
18378  }
18379  // deal with other settings
18380  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
18381  Display->DisplayOffsetV = TempDisplayOffsetV;
18382  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
18383  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
18384  // now set attributes to 1 for all LCs with barriers down
18385  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
18386  {
18388  }
18389  Track->ChangingLCVector.clear();
18390  Track->CalcHLocMinEtc(10);
18392  SetLevel1Mode(27);
18393  if(Level2OperMode == PreStart)
18394  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
18395  {
18396  // then delay unspecified though seems to be 0
18397  PointsFlashDuration = 0.0;
18400  }
18401  else
18402  {
18406  }
18407  RlyFile = true;
18408  SetCaption(3);
18410  }
18411  }
18412  else
18413  {
18414  ShowMessage("Session file integrity check failed, unable to load " + LoadSessionDialog->FileName);
18415  }
18416  Screen->Cursor = TCursor(-2); // Arrow;
18417  }
18418  Utilities->CallLogPop(1146);
18419  }
18420  catch(const Exception &e)
18421  {
18422  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
18423  {
18424  Screen->Cursor = TCursor(-2); // Arrow;
18425  OutputLog1->Caption = "";
18426  OutputLog2->Caption = "";
18427  OutputLog3->Caption = "";
18428  OutputLog4->Caption = "";
18429  OutputLog5->Caption = "";
18430  OutputLog6->Caption = "";
18431  OutputLog7->Caption = "";
18432  OutputLog8->Caption = "";
18433  OutputLog9->Caption = "";
18434  OutputLog10->Caption = "";
18435  UnicodeString MessageStr =
18436  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
18437 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
18438  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
18439  Application->Terminate();
18440  }
18441  else
18442  {
18443  ErrorLog(41, e.Message);
18444  }
18445  }
18446 }
18447 
18448 // ---------------------------------------------------------------------------
18449 
18450 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
18451 {
18452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
18453  if(Level2OperMode == PreStart)
18454  {
18455  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
18456  }
18457  else
18458  {
18459  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
18460  }
18461  Utilities->SaveFileString(SessionFile, RailwayTitle);
18462  Utilities->SaveFileString(SessionFile, TimetableTitle);
18463  Utilities->SaveFileBool(SessionFile, PreferredRoute);
18464  Utilities->SaveFileBool(SessionFile, PreferredRoute);
18465 // changed at v2.7.0, was ConsecSignalsRoute here but if different to PreferredRoute (as can be from v2.7.0) then have
18466  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
18467 // error if try to load with an earlier prog version. ConsecSignalsRoute now moved to end of session file
18468  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
18469  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
18474  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
18475  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
18476  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
18477  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
18478  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
18479  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
18480  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
18481  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
18482  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
18483  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
18484 
18506  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
18507  Utilities->CallLogPop(1211);
18508 }
18509 
18510 // ---------------------------------------------------------------------------
18511 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
18512 {
18513  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
18514  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
18515 
18516  if(OpMode == "PreStart")
18517  {
18519  }
18520  else
18521  {
18523  }
18524  RailwayTitle = Utilities->LoadFileString(SessionFile);
18525  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
18526 
18527  TimetableTitle = Utilities->LoadFileString(SessionFile);
18528  PreferredRoute = Utilities->LoadFileBool(SessionFile);
18529  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
18530  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
18531  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
18532  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
18537  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
18538  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
18539  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
18540  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
18541  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
18542  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
18543  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
18544  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
18545  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
18546  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
18547 
18555  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
18569  Utilities->CallLogPop(1212);
18570 }
18571 
18572 // ---------------------------------------------------------------------------
18573 
18574 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
18575 {
18576  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
18577 
18578  AnsiString OpMode = "";
18579 
18580  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
18581  {
18582  Utilities->CallLogPop(1767);
18583  return(false);
18584  }
18585  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
18586  {
18587  Utilities->CallLogPop(1768);
18588  return(false);
18589  }
18590  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
18591  {
18592  Utilities->CallLogPop(1213);
18593  return(false);
18594  }
18595  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
18596  {
18597  Utilities->CallLogPop(1214);
18598  return(false);
18599  }
18600  if(!Utilities->CheckFileBool(SessionFile))
18601  {
18602  Utilities->CallLogPop(1216);
18603  return(false);
18604  }
18605  if(!Utilities->CheckFileBool(SessionFile))
18606  {
18607  Utilities->CallLogPop(1217);
18608  return(false);
18609  }
18610  if(!Utilities->CheckFileBool(SessionFile))
18611  {
18612  Utilities->CallLogPop(1218);
18613  return(false);
18614  }
18615  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18616  {
18617  Utilities->CallLogPop(1409);
18618  return(false);
18619  }
18620  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18621  {
18622  Utilities->CallLogPop(1486);
18623  return(false);
18624  }
18625  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18626  {
18627  Utilities->CallLogPop(1487);
18628  return(false);
18629  }
18630  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18631  {
18632  Utilities->CallLogPop(1488);
18633  return(false);
18634  }
18635  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18636  {
18637  Utilities->CallLogPop(1489);
18638  return(false);
18639  }
18640  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
18641  {
18642  Utilities->CallLogPop(1528);
18643  return(false);
18644  }
18645  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18646  {
18647  Utilities->CallLogPop(1725);
18648  return(false);
18649  }
18650  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18651  {
18652  Utilities->CallLogPop(1726);
18653  return(false);
18654  }
18655  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18656  {
18657  Utilities->CallLogPop(1727);
18658  return(false);
18659  }
18660  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18661  {
18662  Utilities->CallLogPop(1728);
18663  return(false);
18664  }
18665  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18666  {
18667  Utilities->CallLogPop(1730);
18668  return(false);
18669  }
18670  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18671  {
18672  Utilities->CallLogPop(1731);
18673  return(false);
18674  }
18675  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18676  {
18677  Utilities->CallLogPop(1732);
18678  return(false);
18679  }
18680  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18681  {
18682  Utilities->CallLogPop(1733);
18683  return(false);
18684  }
18685  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18686  {
18687  Utilities->CallLogPop(1734);
18688  return(false);
18689  }
18690  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
18691  {
18692  Utilities->CallLogPop(1789);
18693  return(false);
18694  }
18695  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18696  {
18697  Utilities->CallLogPop(1737);
18698  return(false);
18699  }
18700  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18701  {
18702  Utilities->CallLogPop(1738);
18703  return(false);
18704  }
18705  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18706  {
18707  Utilities->CallLogPop(1739);
18708  return(false);
18709  }
18710  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18711  {
18712  Utilities->CallLogPop(1740);
18713  return(false);
18714  }
18715  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18716  {
18717  Utilities->CallLogPop(1741);
18718  return(false);
18719  }
18720  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18721  {
18722  Utilities->CallLogPop(1742);
18723  return(false);
18724  }
18725  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18726  {
18727  Utilities->CallLogPop(1743);
18728  return(false);
18729  }
18730  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18731  {
18732  Utilities->CallLogPop(1744);
18733  return(false);
18734  }
18735  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18736  {
18737  Utilities->CallLogPop(1745);
18738  return(false);
18739  }
18740  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18741  {
18742  Utilities->CallLogPop(1746);
18743  return(false);
18744  }
18745  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18746  {
18747  Utilities->CallLogPop(1747);
18748  return(false);
18749  }
18750  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18751  {
18752  Utilities->CallLogPop(1748);
18753  return(false);
18754  }
18755  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18756  {
18757  Utilities->CallLogPop(1749);
18758  return(false);
18759  }
18760  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18761  {
18762  Utilities->CallLogPop(1750);
18763  return(false);
18764  }
18765  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18766  {
18767  Utilities->CallLogPop(1751);
18768  return(false);
18769  }
18770  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
18771  {
18772  Utilities->CallLogPop(1752);
18773  return(false);
18774  }
18775  if(!Utilities->CheckFileDouble(SessionFile))
18776  {
18777  Utilities->CallLogPop(1753);
18778  return(false);
18779  }
18780  if(!Utilities->CheckFileDouble(SessionFile))
18781  {
18782  Utilities->CallLogPop(1754);
18783  return(false);
18784  }
18785  if(!Utilities->CheckFileDouble(SessionFile))
18786  {
18787  Utilities->CallLogPop(1755);
18788  return(false);
18789  }
18790  if(!Utilities->CheckFileDouble(SessionFile))
18791  {
18792  Utilities->CallLogPop(1756);
18793  return(false);
18794  }
18795  if(!Utilities->CheckFileDouble(SessionFile))
18796  {
18797  Utilities->CallLogPop(1757);
18798  return(false);
18799  }
18800  Utilities->CallLogPop(1219);
18801  return(true);
18802 }
18803 
18804 // ---------------------------------------------------------------------------
18805 
18806 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
18807 {
18808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
18809  if(!FileExists(TempTTFileName))
18810  {
18811  Utilities->CallLogPop(1862);
18812  return(false);
18813  }
18814  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
18815  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
18816 
18817  int Handle = FileOpen(TempTTFileName, fmOpenRead);
18818  int Count = 0;
18819 
18820  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
18821  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
18822  // then, but nevertheless have 10 retries before giving message to be on safe side
18823  {
18824  Handle = FileOpen(TempTTFileName, fmOpenRead);
18825  Count++;
18826  Delay(1, 50); // 50mSec delay between tries
18827  if(Count > 10)
18828  {
18829  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
18830  Utilities->CallLogPop(1221);
18831  return(false);
18832  }
18833  }
18834 
18835  char *Buffer = new char[10000];
18836  int BytesRead;
18837 
18838  while(true)
18839  {
18840  BytesRead = FileRead(Handle, Buffer, 10000);
18841  SessionFile.write(Buffer, BytesRead);
18842  if(BytesRead < 10000)
18843  {
18844  break;
18845  }
18846  }
18847  delete[]Buffer;
18848  FileClose(Handle);
18849 
18850  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
18851  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
18852 
18853  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
18854 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
18855  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
18856  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
18857  {
18858  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
18859  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
18860  {
18861  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
18862  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
18863  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
18864  }
18865  }
18866  Utilities->CallLogPop(1220);
18867  return(true);
18868 }
18869 
18870 // ---------------------------------------------------------------------------
18871 
18872 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
18873 {
18874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
18875  if(!FileExists(TimetableFileName))
18876  {
18877  Utilities->CallLogPop(1863);
18878  return(false);
18879  }
18880  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
18881  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
18882 
18883  int Handle = FileOpen(TimetableFileName, fmOpenRead);
18884  int Count = 0;
18885 
18886  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
18887  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
18888  // then, but nevertheless have 10 retries before giving message to be on safe side
18889  {
18890  Handle = FileOpen(TimetableFileName, fmOpenRead);
18891  Count++;
18892  Delay(5, 50); // 50mSec delay between tries
18893  if(Count > 10)
18894  {
18895  Utilities->CallLogPop(1835);
18896  return(false);
18897  }
18898  }
18899 
18900  char *Buffer = new char[10000];
18901  int BytesRead;
18902 
18903  while(true)
18904  {
18905  BytesRead = FileRead(Handle, Buffer, 10000);
18906  ErrorFile.write(Buffer, BytesRead);
18907  if(BytesRead < 10000)
18908  {
18909  break;
18910  }
18911  }
18912  delete[]Buffer;
18913  FileClose(Handle);
18914 
18915  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
18916  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
18917 
18918  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
18919  Utilities->CallLogPop(1836);
18920  return(true);
18921 }
18922 
18923 // ---------------------------------------------------------------------------
18924 
18925 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
18926 // the .ttb section is delimited by "***End***"
18927 // create the temporary timetable file in the working folder exactly like the original
18928 {
18929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
18930  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
18931  TrainController->SSHigh = false;
18932  TrainController->MRSHigh = false;
18933  TrainController->MRSLow = false;
18934  TrainController->MassHigh = false;
18935  TrainController->BFHigh = false;
18936  TrainController->BFLow = false;
18937  TrainController->PwrHigh = false;
18938  TrainController->SigSHigh = false;
18939  TrainController->SigSLow = false;
18940  if((TempTTFileName != "") && FileExists(TempTTFileName))
18941  {
18942  DeleteFile(TempTTFileName);
18943  }
18944  int TempTTFileNumber = 0;
18945 
18946  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
18947  {
18948  TempTTFileNumber++;
18949  }
18950  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
18951 
18952  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
18953  int Count;
18954  char Zero = '\0';
18955 
18956  if(!TTBFile.fail())
18957  {
18958  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
18959  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
18960  if(TempChar == '\n')
18961  {
18962  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
18963  }
18964  if(!SessionFile.getline(Buffer, 10000, '\0'))
18965  {
18966  TTBFile.close();
18967  DeleteFile(TempTTFileName);
18968  delete[]Buffer;
18969  Utilities->CallLogPop(1222);
18970  return(false);
18971  }
18972  Count = 0;
18973  for(int x = 0; x < 10000; x++)
18974  {
18975  if(Buffer[x] != '\0')
18976  {
18977  Count++;
18978  }
18979  else
18980  {
18981  break;
18982  }
18983  }
18984  while(AnsiString(Buffer) != "***End***")
18985  {
18986  TTBFile.write(Buffer, Count);
18987  TTBFile.write(&Zero, 1);
18988 // TTBFile.write(&NewLine, 1);
18989  if(!SessionFile.getline(Buffer, 10000, '\0'))
18990  {
18991  TTBFile.close();
18992  DeleteFile(TempTTFileName);
18993  delete[]Buffer;
18994  Utilities->CallLogPop(1223);
18995  return(false);
18996  }
18997  Count = 0;
18998  for(int x = 0; x < 10000; x++)
18999  {
19000  if(Buffer[x] != '\0')
19001  {
19002  Count++;
19003  }
19004  else
19005  {
19006  break;
19007  }
19008  }
19009  }
19010  TTBFile.close();
19011  delete[]Buffer;
19012 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
19013 // now create the internal timetable from the .tmp file
19014  bool GiveMessagesFalse = false;
19015  bool CheckLocationsExistInRailwayTrue = true;
19016  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
19017  {
19018  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
19019  if(TTBLFile.is_open())
19020  {
19021  bool SessionFileTrue = true;
19022  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
19023  {
19024  TTBLFile.close();
19025  DeleteFile(TempTTFileName);
19026  Utilities->CallLogPop(1224);
19027  return(false);
19028  }
19029  }
19030  else
19031  {
19032  DeleteFile(TempTTFileName);
19033  Utilities->CallLogPop(1225);
19034  return(false);
19035  }
19036  } // if(FileIntegrityCheck(TTBFileName.c_str()))
19037  else
19038  {
19039  DeleteFile(TempTTFileName);
19040  Utilities->CallLogPop(1226);
19041  return(false);
19042  }
19043 // DeleteFile(TempTTFileName); no, need to save it for later session saves
19044 
19045  // now need to load the TrainOperatingData so can be loaded back into the timetable
19046  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
19047  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
19048  {
19049  Utilities->CallLogPop(1811);
19050  return(false);
19051  }
19052  for(int x = 0; x < NumberOfTrainEntries; x++)
19053  {
19054  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
19055  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
19056  {
19057  Utilities->CallLogPop(1812);
19058  return(false);
19059  }
19060  for(int y = 0; y < NumberOfTrains; y++)
19061  {
19062  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
19063  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
19064  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
19065  }
19066  }
19067  Utilities->CallLogPop(1227);
19068  return(true);
19069  }
19070  else
19071  {
19072  Utilities->CallLogPop(1228);
19073  return(false);
19074  }
19075 }
19076 
19077 // ---------------------------------------------------------------------------
19078 
19079 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
19080 // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
19081 // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
19082 // trying to build a timetable - that's done during load
19083 {
19084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
19085  AnsiString OutString;
19086 
19087  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
19088  {
19089  Utilities->CallLogPop(1229);
19090  return(false);
19091  }
19092  while(OutString != "***End***")
19093  {
19094  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
19095  {
19096  Utilities->CallLogPop(1230);
19097  return(false);
19098  }
19099  }
19100 // now need to check the TrainOperatingData, which was saved in text mode
19101  if(SessionFile.fail())
19102  {
19103  Utilities->CallLogPop(1231);
19104  return(false);
19105  }
19106  int NumberOfTrainEntries;
19107 
19108  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
19109  {
19110  Utilities->CallLogPop(1232);
19111  return(false);
19112  }
19113  for(int x = 0; x < NumberOfTrainEntries; x++)
19114  {
19115  int NumberOfTrains;
19116  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
19117  {
19118  Utilities->CallLogPop(1233);
19119  return(false);
19120  }
19121  for(int y = 0; y < NumberOfTrains; y++)
19122  {
19123  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
19124  {
19125  Utilities->CallLogPop(1234);
19126  return(false);
19127  }
19128  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
19129  {
19130  Utilities->CallLogPop(1235);
19131  return(false);
19132  }
19133  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
19134  {
19135  Utilities->CallLogPop(1236);
19136  return(false);
19137  }
19138  }
19139  }
19140  Utilities->CallLogPop(1237);
19141  return(true);
19142 }
19143 
19144 // ---------------------------------------------------------------------------
19145 
19146 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
19147 {
19148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
19149  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
19150  bool EndOfFile = false;
19151  int Count = 0;
19152  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
19153 
19154  while(!EndOfFile)
19155  {
19156  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19157  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
19158  {
19159  // may still have eof even if read a line (no CRLF at end), and
19160  // if so need to process it
19161  EndOfFile = true;
19162  break;
19163  }
19164  AnsiString OneLine(TrainTimetableString);
19165  bool FinalCallTrue = true;
19166  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
19167  CheckLocationsExistInRailway)) // get rid of lines before the start time
19168  {
19169  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19170  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19171  {
19172  TTBLFile.close();
19173  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
19174  }
19175  OneLine = AnsiString(TrainTimetableString);
19176  }
19177  // here when have accepted the start time
19178  if(Count == 0)
19179  {
19180  Count++; // increment past the start time
19181  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
19182  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19183  {
19184  EndOfFile = true;
19185  OneLine = "";
19186  }
19187  else
19188  {
19189  OneLine = AnsiString(TrainTimetableString);
19190  }
19191  }
19192  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
19193  {
19194  TTBLFile.close();
19195  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
19196  }
19197  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
19198  {
19199  TTBLFile.close();
19200  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
19201  }
19202  Count++;
19203  }
19204  TTBLFile.close();
19205  delete[]TrainTimetableString;
19206  bool TwoLocationFlag; //not used in LoadFile
19207 // here when first pass actions completed successfully
19208  if(!TrainController->SecondPassActions(0, GiveMessages, TwoLocationFlag)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
19209  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
19210  // messages given in function if errors & vector cleared
19211  {
19212  if(GiveMessages)
19213  {
19214  ShowMessage("Timetable secondary integrity check failed - unable to load");
19215  }
19216  Utilities->CallLogPop(1238);
19217  return(false);
19218  }
19219  else
19220  {
19221 // TimetableLoaded = true;
19222  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
19223  {
19224  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
19225  {
19226  if(TimetableDialog->FileName[x] == '\\')
19227  {
19228  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
19229  SetCaption(4);
19230  break;
19231  }
19232  }
19233  }
19234 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
19235  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
19236  {
19237  Level1Mode = BaseMode;
19238  SetLevel1Mode(28);
19239  }
19240  }
19241  Utilities->CallLogPop(1239);
19242  return(true);
19243 }
19244 
19245 // ---------------------------------------------------------------------------
19246 
19247 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
19248 {
19249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
19250  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
19251  bool EndOfFile = false;
19252  int Count = 0;
19253  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
19254 
19255  while(!EndOfFile)
19256  {
19257  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19258  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
19259  {
19260  // may still have eof even if read a line (no CRLF at end), and
19261  // if so need to process it
19262  EndOfFile = true;
19263  break;
19264  }
19265  AnsiString OneLine(TrainTimetableString);
19266  bool FinalCallTrue = true;
19267  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
19268  CheckLocationsExistInRailway)) // get rid of lines before the start time
19269  {
19270  TTBLFile.getline(TrainTimetableString, 10000, '\0');
19271  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19272  {
19273  TTBLFile.close();
19274  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
19275  }
19276  OneLine = AnsiString(TrainTimetableString);
19277  }
19278  // here when have accepted the start time
19279  if(Count == 0)
19280  {
19281  Count++; // increment past the start time
19282  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
19283  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
19284  {
19285  EndOfFile = true;
19286  OneLine = "";
19287  }
19288  else
19289  {
19290  OneLine = AnsiString(TrainTimetableString);
19291  }
19292  }
19293  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
19294  {
19295  TTBLFile.close();
19296  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
19297  }
19298  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
19299  {
19300  TTBLFile.close();
19301  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
19302  }
19303  Count++;
19304  }
19305  TTBLFile.close();
19306  delete[]TrainTimetableString;
19307  bool TwoLocationFlag;
19308 // here when first pass actions completed successfully
19309  if(!TrainController->SecondPassActions(1, GiveMessages, TwoLocationFlag)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
19310  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
19311  // messages given in function if errors & vector cleared
19312  {
19313 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
19314 // above dropped in v2.4.0 as all called functions give own messages
19315  Utilities->CallLogPop(1665);
19316  return(false);
19317  }
19318  else if(TwoLocationFlag) //i.e returns true but have services with two or more locations without a cdt between //added at v2.9.1
19319  {
19320  AnsiString AllServices = "", Suffix = "";
19321  int Count = 1;
19323  {
19324  TwoLocationNamePanel->Top = TimetableEditPanel->Top + ((TimetableEditPanel->Height - TwoLocationNamePanel->Height) / 2);
19325  TwoLocationNamePanel->Left = TimetableEditPanel->Left + ((TimetableEditPanel->Width - TwoLocationNamePanel->Width) / 2);
19326  for(TTrainController::TServiceCallingLocsList::iterator TLLIt = TrainController->TwoLocationList.begin(); TLLIt != TrainController->TwoLocationList.end(); TLLIt++)
19327  {
19328  if(Count <= 5)
19329  {
19330  AllServices = AllServices + *TLLIt + ", ";
19331  }
19332  Count++;
19333  }
19334  if(Count > 6) //if exactly 5 entered then Count will be 6, Count always 1 more than entered
19335  {
19336  Suffix = "(more than 5, first 5 are) ";
19337  }
19338  if(Count > 2) //more than 1
19339  {
19340  TwoLocationNameLabel->Caption = "The following services have two or more locations with the same name without a change of\n"
19341  "direction between them. If this isn't intended then please correct them.\n\n"
19342  "Before ticking the check box please be sure that all services are correct.\n\n"
19343  "Services: " + Suffix + " " + AllServices;
19344  }
19345  else
19346  {
19347  TwoLocationNameLabel->Caption = "The following service has two or more locations with the same name without a change of\n"
19348  "direction between them. If this isn't intended then please correct it.\n\n"
19349  "Service: " + AllServices;
19350  }
19351  TwoLocationNamePanel->Visible = true;
19352  TwoLocationNamePanel->BringToFront();
19353  ShowHideTTButton->Enabled = false;
19354  ExitTTModeButton->Enabled = false;
19355  TimetableEditPanel->Enabled = false;
19356  }
19357  }
19358  Utilities->CallLogPop(1666);
19359  return(true);
19360 }
19361 
19362 // ---------------------------------------------------------------------------
19363 
19364 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
19365 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
19366 relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
19367 before loading.
19368 
19369 Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
19370 all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
19371 which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
19372 in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
19373 
19374 Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
19375 would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
19376 */
19377 {
19378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
19379  std::ifstream InFile(FileName.c_str());
19380 // first pass as far as timetable
19381  int NumberOfActiveElements;
19382  bool GraphicsFollow = false;
19383 
19384  if(InFile.is_open())
19385  {
19387  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float at v2.3.0
19388  {
19389  InFile.close();
19390  Utilities->CallLogPop(1240);
19391  return(false);
19392  }
19393  if(!CheckInterface(0, InFile))
19394  {
19395  InFile.close();
19396  Utilities->CallLogPop(1241);
19397  return(false);
19398  }
19399  // check track elements
19400  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
19401  {
19402  InFile.close();
19403  Utilities->CallLogPop(1242);
19404  return(false);
19405  }
19406  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
19407  {
19408  InFile.close();
19409  Utilities->CallLogPop(1243);
19410  return(false);
19411  }
19412  if(InFile.fail())
19413  {
19414  InFile.close();
19415  Utilities->CallLogPop(1244);
19416  return(false);
19417  }
19418  // check text elements
19419  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
19420  {
19421  InFile.close();
19422  Utilities->CallLogPop(1245);
19423  return(false);
19424  }
19425  if(!TextHandler->CheckTextElementsInFile(1, InFile))
19426  {
19427  InFile.close();
19428  Utilities->CallLogPop(1246);
19429  return(false);
19430  }
19431  if(InFile.fail())
19432  {
19433  InFile.close();
19434  Utilities->CallLogPop(1247);
19435  return(false);
19436  }
19437  // check PrefDir elements
19438  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
19439  {
19440  InFile.close();
19441  Utilities->CallLogPop(1248);
19442  return(false);
19443  }
19444  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
19445  {
19446  InFile.close();
19447  Utilities->CallLogPop(1249);
19448  return(false);
19449  }
19450  if(InFile.fail())
19451  {
19452  InFile.close();
19453  Utilities->CallLogPop(1250);
19454  return(false);
19455  }
19456  // check graphics
19457  if(GraphicsFollow)
19458  {
19459  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
19460  {
19461  InFile.close();
19462  Utilities->CallLogPop(2187);
19463  return(false);
19464  }
19465  if(InFile.fail())
19466  {
19467  InFile.close();
19468  Utilities->CallLogPop(2188);
19469  return(false);
19470  }
19471  }
19472  // check routes
19473  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
19474  {
19475  InFile.close();
19476  Utilities->CallLogPop(1251);
19477  return(false);
19478  }
19479  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
19480  {
19481  InFile.close();
19482  Utilities->CallLogPop(1252);
19483  return(false);
19484  }
19485  if(InFile.fail())
19486  {
19487  InFile.close();
19488  Utilities->CallLogPop(1253);
19489  return(false);
19490  }
19491  // check LockedRoutes
19492  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
19493  {
19494  InFile.close();
19495  Utilities->CallLogPop(1254);
19496  return(false);
19497  }
19498  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
19499  {
19500  InFile.close();
19501  Utilities->CallLogPop(1255);
19502  return(false);
19503  }
19504  if(InFile.fail())
19505  {
19506  InFile.close();
19507  Utilities->CallLogPop(1256);
19508  return(false);
19509  }
19510  // check ContinuationAutoSigs
19511  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
19512  {
19513  InFile.close();
19514  Utilities->CallLogPop(1257);
19515  return(false);
19516  }
19518  {
19519  InFile.close();
19520  Utilities->CallLogPop(1258);
19521  return(false);
19522  }
19523  if(InFile.fail())
19524  {
19525  InFile.close();
19526  Utilities->CallLogPop(1259);
19527  return(false);
19528  }
19529  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
19530  AnsiString TempString = Utilities->LoadFileString(InFile);
19531  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
19532  {
19533  InFile.close();
19534  Utilities->CallLogPop(1964);
19535  return(false);
19536  }
19537  if(TempString == "***BarriersDownVector***")
19538  {
19539  if(!Track->CheckActiveLCVector(0, InFile))
19540  {
19541  InFile.close();
19542  Utilities->CallLogPop(1965);
19543  return(false);
19544  }
19545  if(InFile.fail())
19546  {
19547  InFile.close();
19548  Utilities->CallLogPop(1966);
19549  return(false);
19550  }
19551  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
19552  {
19553  InFile.close();
19554  Utilities->CallLogPop(1260);
19555  return(false);
19556  }
19557  }
19558  // check timetable (marker string already checked immediately above)
19559  if(!CheckTimetableFromSessionFile(0, InFile))
19560  {
19561  InFile.close();
19562  Utilities->CallLogPop(1261);
19563  return(false);
19564  }
19565  if(InFile.fail())
19566  {
19567  InFile.close();
19568  Utilities->CallLogPop(1262);
19569  return(false);
19570  }
19571  }
19572  else
19573  {
19574  InFile.close();
19575 // ShowMessage("Session file failed to open, reason not known, unable to load session."); message given in calling function if returns false
19576  Utilities->CallLogPop(1263);
19577  return(false);
19578  }
19579 // now ready for the 2nd pass for timetable loading and checking
19580  InFile.close();
19581  InFile.open(FileName.c_str());
19582  if(InFile.is_open())
19583  {
19585  {
19586  InFile.close();
19587  Utilities->CallLogPop(1264);
19588  return(false);
19589  }
19590  if(!CheckInterface(1, InFile))
19591  {
19592  InFile.close();
19593  Utilities->CallLogPop(1265);
19594  return(false);
19595  }
19596  // load track elements
19597  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
19598  {
19599  InFile.close();
19600  Utilities->CallLogPop(1266);
19601  return(false);
19602  }
19603  bool GraphicsFollow = false;
19604  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
19605  if(InFile.fail())
19606  {
19607  InFile.close();
19608  Utilities->CallLogPop(1267);
19609  return(false);
19610  }
19611  // check text elements
19612  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
19613  {
19614  InFile.close();
19615  Utilities->CallLogPop(1268);
19616  return(false);
19617  }
19618  if(!TextHandler->CheckTextElementsInFile(2, InFile))
19619  {
19620  InFile.close();
19621  Utilities->CallLogPop(1269);
19622  return(false);
19623  }
19624  if(InFile.fail())
19625  {
19626  InFile.close();
19627  Utilities->CallLogPop(1270);
19628  return(false);
19629  }
19630  // check PrefDir elements
19631  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
19632  {
19633  InFile.close();
19634  Utilities->CallLogPop(1271);
19635  return(false);
19636  }
19637  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
19638  {
19639  InFile.close();
19640  Utilities->CallLogPop(1272);
19641  return(false);
19642  }
19643  if(InFile.fail())
19644  {
19645  InFile.close();
19646  Utilities->CallLogPop(1273);
19647  return(false);
19648  }
19649  // check graphics
19650  if(GraphicsFollow)
19651  {
19652  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
19653  {
19654  InFile.close();
19655  Utilities->CallLogPop(2189);
19656  return(false);
19657  }
19658  if(InFile.fail())
19659  {
19660  InFile.close();
19661  Utilities->CallLogPop(2190);
19662  return(false);
19663  }
19664  }
19665  // check routes
19666  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
19667  {
19668  InFile.close();
19669  Utilities->CallLogPop(1274);
19670  return(false);
19671  }
19672  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
19673  {
19674  InFile.close();
19675  Utilities->CallLogPop(1275);
19676  return(false);
19677  }
19678  if(InFile.fail())
19679  {
19680  InFile.close();
19681  Utilities->CallLogPop(1276);
19682  return(false);
19683  }
19684  // check LockedRoutes
19685  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
19686  {
19687  InFile.close();
19688  Utilities->CallLogPop(1277);
19689  return(false);
19690  }
19691  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
19692  {
19693  InFile.close();
19694  Utilities->CallLogPop(1278);
19695  return(false);
19696  }
19697  if(InFile.fail())
19698  {
19699  InFile.close();
19700  Utilities->CallLogPop(1279);
19701  return(false);
19702  }
19703  // check ContinuationAutoSigs
19704  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
19705  {
19706  InFile.close();
19707  Utilities->CallLogPop(1280);
19708  return(false);
19709  }
19711  {
19712  InFile.close();
19713  Utilities->CallLogPop(1281);
19714  return(false);
19715  }
19716  if(InFile.fail())
19717  {
19718  InFile.close();
19719  Utilities->CallLogPop(1282);
19720  return(false);
19721  }
19722  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
19723  AnsiString TempString = Utilities->LoadFileString(InFile);
19724  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
19725  {
19726  InFile.close();
19727  Utilities->CallLogPop(1967);
19728  return(false);
19729  }
19730  if(TempString == "***BarriersDownVector***")
19731  {
19732  if(!Track->CheckActiveLCVector(0, InFile))
19733  {
19734  InFile.close();
19735  Utilities->CallLogPop(1968);
19736  return(false);
19737  }
19738  if(InFile.fail())
19739  {
19740  InFile.close();
19741  Utilities->CallLogPop(1969);
19742  return(false);
19743  }
19744  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
19745  {
19746  InFile.close();
19747  Utilities->CallLogPop(1283);
19748  return(false);
19749  }
19750  }
19751  // check timetable (marker string already checked)
19752  if(!LoadTimetableFromSessionFile(1, InFile))
19753  {
19754  InFile.close();
19755  Utilities->CallLogPop(1284);
19756  return(false);
19757  }
19758  if(InFile.fail())
19759  {
19760  InFile.close();
19761  Utilities->CallLogPop(1285);
19762  return(false);
19763  }
19764  // check timetable clock
19765  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
19766  {
19767  InFile.close();
19768  Utilities->CallLogPop(1286);
19769  return(false);
19770  }
19771  if(!Utilities->CheckFileDouble(InFile))
19772  {
19773  InFile.close();
19774  Utilities->CallLogPop(1287);
19775  return(false);
19776  }
19777  // check trains
19778  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
19779  {
19780  InFile.close();
19781  Utilities->CallLogPop(1288);
19782  return(false);
19783  }
19784  if(!TrainController->CheckSessionTrains(0, InFile))
19785  {
19786  InFile.close();
19787  Utilities->CallLogPop(1289);
19788  return(false);
19789  }
19790  if(InFile.fail())
19791  {
19792  InFile.close();
19793  Utilities->CallLogPop(1290);
19794  return(false);
19795  }
19796  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
19797  {
19798  InFile.close();
19799  Utilities->CallLogPop(1291);
19800  return(false);
19801  }
19802  if(!CheckPerformanceFile(0, InFile))
19803  {
19804  InFile.close();
19805  Utilities->CallLogPop(1292);
19806  return(false);
19807  }
19808  char TempChar;
19809  InFile.get(TempChar);
19810  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
19811  {
19812  InFile.get(TempChar);
19813  }
19814  if(!InFile.eof()) // additional checks needed
19815  {
19816  if(!Utilities->CheckFileString(InFile))
19817  {
19818  InFile.close();
19819  Utilities->CallLogPop(2198);
19820  return(false);
19821  }
19822  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
19823  {
19824  InFile.close();
19825  Utilities->CallLogPop(2199);
19826  return(false);
19827  }
19828  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
19829  {
19830  InFile.close();
19831  Utilities->CallLogPop(2200);
19832  return(false);
19833  }
19834  // now check any failed trains along with their OriginalPowerAtRail values
19835  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
19836  int IDVal;
19837  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
19838  {
19839  InFile.close();
19840  Utilities->CallLogPop(2201);
19841  return(false);
19842  }
19843  double PowerDouble;
19844  while(IDVal != -1)
19845  {
19846  Utilities->CheckFileDouble(InFile); // original power
19847  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
19848  {
19849  InFile.close();
19850  Utilities->CallLogPop(2202);
19851  return(false);
19852  }
19853  }
19854  }
19855  InFile.close();
19856  }
19857  else
19858  {
19859  InFile.close();
19860  Utilities->CallLogPop(1293);
19861  return(false);
19862  }
19863  Utilities->CallLogPop(1294);
19864  return(true);
19865 }
19866 
19867 // ---------------------------------------------------------------------------
19868 
19869 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
19870 // Note that the file integrity has already been checked using CheckPerformanceFile
19871 {
19872  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
19873  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
19874  char *Buffer = new char[1000];
19875  char TempChar;
19876 
19877  InFile.get(TempChar); // '\n'
19878  InFile.getline(Buffer, 1000);
19879  TempString = AnsiString(Buffer);
19880  while(TempString != "***End of performance file***")
19881  {
19882  PerformanceLogBox->Lines->Add(TempString);
19883  Utilities->PerformanceFile << TempString.c_str() << '\n';
19884  InFile.getline(Buffer, 1000);
19885  TempString = AnsiString(Buffer);
19886  }
19887  delete[]Buffer;
19888  Utilities->CallLogPop(1295);
19889 }
19890 
19891 // ---------------------------------------------------------------------------
19892 
19893 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
19894 {
19895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
19896  AnsiString TempString = "";
19897  char TempChar;
19898 
19899  InFile.get(TempChar);
19900  if(TempChar != '\n')
19901  {
19902  Utilities->CallLogPop(1296);
19903  return(false);
19904  }
19905  if(!Utilities->CheckAndReadFileString(InFile, TempString))
19906  {
19907  Utilities->CallLogPop(1297);
19908  return(false);
19909  }
19910  while(TempString != "***End of performance file***")
19911  {
19912  if(!Utilities->CheckAndReadFileString(InFile, TempString))
19913  {
19914  Utilities->CallLogPop(1298);
19915  return(false);
19916  }
19917  }
19918  Utilities->CallLogPop(1299);
19919  return(true);
19920 }
19921 
19922 // ---------------------------------------------------------------------------
19923 
19924 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
19925 {
19926  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
19927  AnsiString Text = PerformanceLogBox->Text;
19928 
19929  while(Text != "")
19930  {
19931  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
19932  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
19933  {
19934  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
19935  }
19936  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
19937  while((Text.Length() > 0) && Text[1] < ' ')
19938  {
19939  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
19940  }
19941  OutFile << OneLine.c_str() << '\n';
19942  }
19943  Utilities->CallLogPop(1300);
19944 }
19945 
19946 // ---------------------------------------------------------------------------
19947 
19949 {
19950  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
19951  if(EveryPrefDir->PrefDirSize() > 0)
19952  {
19953  if(AutoSigsFlag)
19954  {
19955  AutoSigsButton->Enabled = false;
19956  SigPrefConsecButton->Enabled = true;
19957  SigPrefNonConsecButton->Enabled = true;
19958  UnrestrictedButton->Enabled = true;
19959  InfoPanel->Visible = true;
19960  if(Level2OperMode == PreStart)
19961  {
19962  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
19963  }
19964  else
19965  {
19966  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
19967  }
19968  InfoCaptionStore = InfoPanel->Caption;
19969  }
19970  else if(PreferredRoute & ConsecSignalsRoute) // added at v2.7.0, was just ConsecSignalsRoute
19971  {
19972  AutoSigsButton->Enabled = true;
19973  SigPrefConsecButton->Enabled = false;
19974  SigPrefNonConsecButton->Enabled = true;
19975  UnrestrictedButton->Enabled = true;
19976  InfoPanel->Visible = true;
19977  if(Level2OperMode == PreStart)
19978  {
19979  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
19980  }
19981  else
19982  {
19983  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
19984  }
19985  InfoCaptionStore = InfoPanel->Caption;
19986  }
19987  else if(PreferredRoute&!ConsecSignalsRoute) // added at v2.7.0
19988  {
19989  AutoSigsButton->Enabled = true;
19990  SigPrefConsecButton->Enabled = true;
19991  SigPrefNonConsecButton->Enabled = false;
19992  UnrestrictedButton->Enabled = true;
19993  InfoPanel->Visible = true;
19994  if(Level2OperMode == PreStart)
19995  {
19996  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
19997  }
19998  else
19999  {
20000  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
20001  }
20002  InfoCaptionStore = InfoPanel->Caption;
20003  }
20004  else
20005  {
20006  AutoSigsButton->Enabled = true;
20007  SigPrefConsecButton->Enabled = true;
20008  SigPrefNonConsecButton->Enabled = true;
20009  UnrestrictedButton->Enabled = false;
20010  InfoPanel->Visible = true;
20011  if(Level2OperMode == PreStart)
20012  {
20013  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20014  }
20015  else
20016  {
20017  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20018  }
20019  InfoCaptionStore = InfoPanel->Caption;
20020  }
20021  }
20022  else
20023  {
20024  AutoSigsButton->Enabled = false;
20025  SigPrefConsecButton->Enabled = false;
20026  SigPrefNonConsecButton->Enabled = false;
20027  UnrestrictedButton->Enabled = false;
20028  InfoPanel->Visible = true;
20029  if(Level2OperMode == PreStart)
20030  {
20031  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20032  }
20033  else
20034  {
20035  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
20036  }
20037  InfoCaptionStore = InfoPanel->Caption;
20038  }
20040  {
20041  RouteCancelButton->Enabled = true;
20042  }
20043  else
20044  {
20045  RouteCancelButton->Enabled = false;
20046  }
20048  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
20051  Utilities->CallLogPop(1301);
20052 }
20053 
20054 // ---------------------------------------------------------------------------
20055 
20057 {
20058  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
20059  if(Display->ZoomOutFlag)
20060  {
20061  InfoPanel->Visible = true;
20062  InfoPanel->Caption = "Left click screen to zoom in at that position";
20063  }
20064  else if(Level2OperMode == Paused)
20065  {
20066  InfoPanel->Visible = true;
20067  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
20068  }
20069 // otherwise do nothing
20070  Utilities->CallLogPop(1302);
20071 }
20072 
20073 // ---------------------------------------------------------------------------
20074 
20076 {
20077  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
20078  RouteCancelButton->Enabled = false;
20079  AutoSigsButton->Enabled = false;
20080  SigPrefConsecButton->Enabled = false;
20081  SigPrefNonConsecButton->Enabled = false;
20082  UnrestrictedButton->Enabled = false;
20083  Utilities->CallLogPop(1303);
20084 }
20085 
20086 // ---------------------------------------------------------------------------
20087 
20089 // no need for call logging as already failed
20090 {
20091 /*
20092  In order to reload as a session file:
20093 
20094  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
20095  strip out:-
20096 
20097  [since adding user graphics after prefdirs need to take this into account]
20098 
20099  up to but excluding ***Interface***
20100  from & including ***ConstructPrefDir PrefDirVector***
20101  to but excluding ***PrefDirs***
20102  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
20103  from & including ***ConstructRoute PrefDirVector***
20104  to but excluding ***Routes***
20105  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
20106  from & including ***No editing timetable*** or ***Editing timetable - [title]***
20107  to but excluding ***TimetableClock***
20108 
20109  need to think more about the later additions & include those but not the v2.8.0 additions (& ensure save trains & perf file)
20110 
20111  and save as a .ssn file.
20112 
20113  In order to load as a railway file: Note if error involves cut/copy etc with prefdirs then need to drop the check of CheckCount
20114 
20115  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
20116 
20117  note or copy the version information at the top of the file
20118  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
20119  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
20120  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
20121  the next line after the two insertions should contain the number of active elements.
20122  strip out ***Text*** including the \0
20123  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
20124  strip out ***UserGraphics*** including the \0 <--this is missing
20125  strip out from & including ***ConstructRoute PrefDirVector*** to the end of the file
20126  rename as .dev or .rly file
20127 
20128  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
20129  'Operate' then 'Exit operation'.
20130 */
20131 
20132 /*
20133  In order to extract a timetable:
20134 
20135  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
20136 
20137  set wordwrap to window on
20138  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
20139  ensure any text before start time ends with /0, otherwise don't need the \0
20140  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
20141  save as a .ttb file
20142 */
20143 
20144  Screen->Cursor = TCursor(-11); // Hourglass;
20145  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
20146  std::ofstream ErrorFile(ErrorFileStr.c_str());
20147 
20148  if(!(ErrorFile.fail()))
20149  {
20150 // save mouse position relative to mainscreen
20151  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
20152  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
20153  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
20154  Utilities->SaveFileString(ErrorFile, MouseStr);
20155  Utilities->SaveFileInt(ErrorFile, MissedTicks);
20156  Utilities->SaveFileInt(ErrorFile, TotalTicks);
20157 
20158 // save call stack
20159  Utilities->SaveFileString(ErrorFile, "***Call stack***");
20160  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
20161  {
20162  AnsiString Item = Utilities->CallLog.at(x);
20163  ErrorFile << Item.c_str() << '\n';
20164  }
20165 // save event log
20166  Utilities->SaveFileString(ErrorFile, "***Event log***");
20167  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
20168  {
20169  AnsiString Item = Utilities->EventLog.at(x);
20170  ErrorFile << Item.c_str() << '\n';
20171  }
20172 // save interface
20173  Utilities->SaveFileString(ErrorFile, "***Interface***");
20174  SaveInterface(1, ErrorFile);
20175 // save track elements
20176  Utilities->SaveFileString(ErrorFile, "***Track***");
20177  if(Track->UserGraphicVector.empty())
20178  {
20179  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
20180  }
20181  else
20182  {
20183  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
20184  }
20185 // save text elements
20186  Utilities->SaveFileString(ErrorFile, "***Text***");
20187  TextHandler->SaveText(3, ErrorFile);
20188 // save ConstructPrefDir PrefDirVector elements
20189  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
20190  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
20191 // save ConstructPrefDir SearchVector elements
20192  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
20193  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
20194 // save EveryPrefDir elements
20195  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
20196  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
20197  if(!Track->UserGraphicVector.empty())
20198  {
20199  // save user graphics
20200  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
20201  Track->SaveUserGraphics(3, ErrorFile);
20202  }
20203 // save ConstructRoute PrefDirVector
20204  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
20205  ConstructRoute->SavePrefDirVector(4, ErrorFile);
20206 // save ConstructRoute SearchVector
20207  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
20208  ConstructRoute->SaveSearchVector(1, ErrorFile);
20209 // save AllRoutes
20210  Utilities->SaveFileString(ErrorFile, "***Routes***");
20211  AllRoutes->SaveRoutes(1, ErrorFile);
20212 // save LockedRoutes
20213  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
20215 // save ContinuationAutoSigEntries
20216  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
20218 // save BarriersDownVector
20219  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
20220  Track->SaveSessionBarriersDownVector(1, ErrorFile);
20221 // save ChangingLCVector
20222  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
20223  Track->SaveChangingLCVector(0, ErrorFile);
20224 // save loaded timetable
20225  if(TimetableTitle == "")
20226  {
20227  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
20228  }
20229  else
20230  {
20231  Utilities->SaveFileString(ErrorFile, "***Timetable***");
20232  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
20233  {
20234  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
20235  }
20236  }
20237 // save editing timetable
20238  if(CreateEditTTTitle == "")
20239  {
20240  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
20241  }
20242  else
20243  {
20244  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
20245  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
20246  {
20247  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
20248  }
20249  }
20250 // save TimetableClock
20251  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
20252  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
20253 // save trains
20254  Utilities->SaveFileString(ErrorFile, "***Trains***");
20255  TrainController->SaveSessionTrains(1, ErrorFile);
20256 // save performance file
20257  Utilities->SaveFileString(ErrorFile, "***Performance file***");
20258  SavePerformanceFile(1, ErrorFile);
20259  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
20260 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
20261  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
20264  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
20265  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
20266  {
20268  {
20271  }
20272  }
20273  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
20274  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
20275 // end of v2.4.1 addition
20276 
20277 // added at v2.7.0 - extras saved later in session file (added at v2.9.2)
20279  Utilities->SaveFileString(ErrorFile, "End of file at v2.7.0");
20280 // end of v2.7.0 addition
20281 
20282 // added at v2.9.1
20288  Utilities->SaveFileString(ErrorFile, "End of v2.9.1 additions"); //changed from '2.9.0' at v2.9.2
20289 // end of v2.9.1 additions
20290 
20291 // addition at v2.8.0 in case of clipboard errors <-- keep at end of file as not wanted in a reconstructed session file
20292  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Height); // extras for new clipboard functions
20293  Utilities->SaveFileInt(ErrorFile, SelectBitmap->Width);
20294  Utilities->SaveFileInt(ErrorFile, SelectBitmapHLoc); // paste location
20295  Utilities->SaveFileInt(ErrorFile, SelectBitmapVLoc);
20296  Utilities->SaveFileInt(ErrorFile, SelectRect.left); // original selection location
20297  Utilities->SaveFileInt(ErrorFile, SelectRect.top);
20298  Utilities->SaveFileInt(ErrorFile, SelectRect.right);
20299  Utilities->SaveFileInt(ErrorFile, SelectRect.bottom);
20300  Utilities->SaveFileString(ErrorFile, "End of clipboard additions");
20301 // end of 2.8.0 addition
20302  ErrorFile.close();
20303  }
20304  else
20305  {
20306  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
20307  }
20308  Screen->Cursor = TCursor(-2); // Arrow
20309 }
20310 
20311 // ---------------------------------------------------------------------------
20312 
20313 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
20314 // the .ttb section is delimited by '\n' followed by "***End***"
20315 // first create a .ttb file in the working folder exactly like the original
20316 
20317 // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
20318 // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
20319 {
20320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
20321  if((TempTTFileName != "") && FileExists(TempTTFileName))
20322  {
20323  DeleteFile(TempTTFileName);
20324  }
20325  int TempTTFileNumber = 0;
20326 
20327  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
20328  {
20329  TempTTFileNumber++;
20330  }
20331  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
20332  int InHandle = FileOpen(InFileName, fmOpenRead);
20333  int Count = 0;
20334 
20335  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
20336  {
20337  InHandle = FileOpen(InFileName, fmOpenRead);
20338  Count++;
20339  Delay(2, 50); // 50mSec delay between tries
20340  if(Count > 10)
20341  {
20342  ShowMessage("Failed to open timetable file, make sure it's spelled correctly, it exists and isn't open in another application");
20343  Utilities->CallLogPop(1400);
20344  return;
20345  }
20346  }
20347  int OutHandle = FileCreate(TempTTFileName);
20348 
20349  Count = 0;
20350  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
20351  {
20352  OutHandle = FileCreate(TempTTFileName);
20353  Count++;
20354  Delay(3, 50); // 50mSec delay between tries
20355  if(Count > 10)
20356  {
20357  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
20358  FileClose(InHandle);
20359  Utilities->CallLogPop(1401);
20360  return;
20361  }
20362  }
20363  int CountIn, CountOut;
20364  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
20365 
20366  while(true)
20367  {
20368  CountIn = FileRead(InHandle, Buffer, 10000);
20369  CountOut = FileWrite(OutHandle, Buffer, CountIn);
20370  if(CountOut != CountIn)
20371  {
20372  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
20373  delete[]Buffer;
20374  FileClose(InHandle);
20375  FileClose(OutHandle);
20376  Utilities->CallLogPop(1402);
20377  return;
20378  }
20379  if(CountIn < 10000)
20380  {
20381  break;
20382  }
20383  }
20384  delete[]Buffer;
20385  FileClose(InHandle);
20386  FileClose(OutHandle);
20387  Utilities->CallLogPop(1403);
20388 }
20389 
20390 // ---------------------------------------------------------------------------
20391 
20392 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
20393 /*
20394  Rules: Platforms are fixed length elements of 100m and aren't changed - no, see note below. Variable length elements can't be less than 20m.
20395  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
20396 
20397  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
20398  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
20399  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
20400  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
20401  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
20402  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
20403  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
20404  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
20405  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
20406  the next XLinkPos for each succeeding element.
20407  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
20408  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
20409  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
20410  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
20411  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
20412  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
20413  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
20414  been set), an error message is given.
20415 */
20416 
20417 {
20418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
20419  bool FoundFlag;
20420 
20421 // ResetDistanceElements(4);
20422  if(ConstructPrefDir->PrefDirSize() == 0)
20423  {
20424  Utilities->CallLogPop(608);
20425  return;
20426  }
20427 // must have PrefDir size of at least 2
20428 
20429 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
20430 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
20431  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
20432  bool NamedLocPresent = false;
20433 
20434  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
20435  {
20436  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
20437  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
20438  if(!FoundFlag)
20439  {
20440  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
20441  }
20442  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
20443  {
20444  VarElements++;
20445  }
20446  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
20447  {
20448  VarElements++; // added in v2.4.0 for no fixed elements
20449  NamedLocPresent = true;
20450 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
20451  }
20452  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
20453  {
20454  if(SpeedLimit != -1)
20455  {
20456  TE.SpeedLimit01 = SpeedLimit;
20457  }
20458  }
20459  else
20460  {
20461  if(SpeedLimit != -1)
20462  {
20463  TE.SpeedLimit23 = SpeedLimit;
20464  }
20465  }
20466  }
20467  if(Distance == -1) // can't return before this as need to set speed limits
20468  {
20469  Utilities->CallLogPop(612);
20470  return;
20471  }
20472  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
20473  {
20474  if(!TooShortMessageSentFlag) //added at v2.9.1
20475  {
20476  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might be too unrealistic.\n\nThis message will not be shown again.");
20477  TooShortMessageSentFlag = true; //added at v2.9.1
20478  }
20479  }
20480  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
20481  {
20482  if(!TooLongMessageSentFlag) //added at v2.9.1
20483  {
20484  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might be too unrealistic.\n\nThis message will not be shown again.");
20485  TooLongMessageSentFlag = true; //added at v2.9.1
20486  }
20487  }
20488 /* if(NamedLocPresent) as was
20489  {
20490  ShowMessage("Named location lengths won't be changed");
20491  }
20492 */
20493 
20494  if((VarElements * 20) > Distance) // removed '+ FixedLength'
20495  {
20496  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
20497  Distance = (VarElements * 20); // removed '+ FixedLength'
20498  }
20499  if(VarElements == 0)
20500  {
20501 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
20502  ShowMessage("No elements selected"); // probably don't need this but include for safety
20503  Utilities->CallLogPop(613);
20504  return;
20505  }
20506 // second pass, set variable lengths
20507  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
20508 
20509  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
20510  {
20511  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
20512  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
20513 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
20514 // {
20515  if(NextLength < 20)
20516  {
20517  NextLength = 20; // added for safety
20518  }
20519  if(TE.TrackType == Points)
20520  {
20521  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
20522  {
20523  TE.Length01 = NextLength;
20524  }
20525  else
20526  {
20527  TE.Length23 = NextLength;
20528  }
20529  }
20530  else
20531  {
20532  if(PrefDirElement.GetELinkPos() < 2)
20533  {
20534  TE.Length01 = NextLength;
20535  }
20536  else
20537  {
20538  TE.Length23 = NextLength;
20539  }
20540  }
20541  RemainingDistance -= NextLength;
20542  RemainingVarElements--;
20543  if(RemainingVarElements > 0)
20544  {
20545  NextLength = RemainingDistance / RemainingVarElements;
20546  }
20547  else
20548  {
20549  NextLength = 20;
20550  }
20551 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
20552  if((RemainingDistance == 0) && (RemainingVarElements != 0))
20553  {
20554  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
20555  }
20556  if((RemainingDistance != 0) && (RemainingVarElements == 0))
20557  {
20558  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
20559  }
20560 */
20561 // }
20562  }
20563  Utilities->CallLogPop(614);
20564 }
20565 
20566 // ---------------------------------------------------------------------------
20567 
20569 {
20570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
20572  {
20573  ShowMessage("Nothing to save!");
20574  }
20575  else
20576  {
20577  if(Track->IsReadyForOperation(false))
20578  {
20579  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
20580  }
20581  else
20582  {
20583  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
20584  }
20585  if(SaveRailwayDialog->Execute())
20586  {
20587  if(SaveRailwayDialog->InitialDir != TPath::GetDirectoryName(SaveRailwayDialog->FileName)) // new at v2.6.0 to retain a new directory
20588  {
20589  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
20590  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
20591  }
20592  Screen->Cursor = TCursor(-11); // Hourglass;
20593  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
20594  AnsiString Extension = "";
20595  if(SaveRailwayDialog->FileName.Length() > 2)
20596  {
20597  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
20598  }
20599  if((Extension == "DEV") || (Track->IsReadyForOperation(true) && (Extension == "RLY"))) // give duplicated location name message if appropriate
20600  {
20601  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
20602  if(!(VecFile.fail()))
20603  {
20607  // save track elements
20608  if(Track->UserGraphicVector.empty())
20609  {
20610  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
20611  }
20612  else
20613  {
20614  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
20615  }
20616  // save text elements
20617  TextHandler->SaveText(1, VecFile);
20618  // save PrefDir elements
20619  EveryPrefDir->SavePrefDirVector(1, VecFile);
20620  if(!Track->UserGraphicVector.empty())
20621  {
20622  // save user graphics
20623  Track->SaveUserGraphics(4, VecFile);
20624  }
20625  VecFile.close();
20626  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
20627  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
20628  {
20629  char LastChar = SavedFileName[SavedFileName.Length()];
20630  if((LastChar == 'y') || (LastChar == 'Y'))
20631  {
20632  RlyFile = true;
20633  }
20634  else
20635  {
20636  RlyFile = false;
20637  }
20638  }
20639  else
20640  {
20641  RlyFile = false;
20642  }
20643  FileChangedFlag = false;
20644  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
20645  {
20646  if(SaveRailwayDialog->FileName[x] == '\\')
20647  {
20648  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
20649  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
20650  SetCaption(7);
20651  break;
20652  }
20653  }
20654  Level1Mode = BaseMode;
20655  SetLevel1Mode(13); // to disable the save option
20656  } // if(!(VecFile.fail()))
20657  else
20658  {
20659  ShowMessage("File open failed prior to save");
20660  }
20661  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
20662  else
20663  {
20664  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
20665  }
20666  Screen->Cursor = TCursor(-2); // Arrow
20667  } // if(SaveRailwayDialog->Execute())
20668 
20669  }
20670  Utilities->CallLogPop(1546);
20671 }
20672 
20673 // ---------------------------------------------------------------------------
20674 
20676 {
20677  // no need for caller or log as only setting values
20678  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackModeEditMenu");
20679  CutMenuItem->Visible = true;
20680  CopyMenuItem->Visible = true;
20681  FlipMenuItem->Visible = true;
20682  MirrorMenuItem->Visible = true;
20683  RotRightMenuItem->Visible = true;
20684  RotLeftMenuItem->Visible = true;
20685  RotateMenuItem->Visible = true;
20686  PasteMenuItem->Visible = true;
20687  DeleteMenuItem->Visible = true;
20688  SelectLengthsMenuItem->Visible = true;
20689  ReselectMenuItem->Visible = true;
20690 // Application->MessageBox(L"Running SetTrackModeEditMenu", L"Message", MB_OK); //debug check
20691  CutMenuItem->Enabled = false;
20692  CopyMenuItem->Enabled = false;
20693  FlipMenuItem->Enabled = false;
20694  MirrorMenuItem->Enabled = false;
20695  RotRightMenuItem->Enabled = false;
20696  RotLeftMenuItem->Enabled = false;
20697  RotateMenuItem->Enabled = false;
20698  PasteMenuItem->Enabled = false;
20699  EditMenu->Enabled = false;
20700  System::WideChar ValidityBuffer[14];
20701  Clipboard()->GetTextBuf(ValidityBuffer, 14);
20702  ClpBrdValid = AnsiString(ValidityBuffer);
20703  Clipboard()->Close();
20704 
20705 // new section for 2.8.0 in case have valid clipboard from another application
20706  if(!SelectionValid)
20707  {
20708  if(ClpBrdValid == "RlyClpBrdCopy")
20709  {
20710  PasteMenuItem->Enabled = true;
20711  if(Level1Mode == TrackMode)
20712  {
20713  EditMenu->Enabled = true;
20714  }
20715  CopySelected = true;
20716  Track->CopyFlag = true;
20717 // Level1Mode = TrackMode;
20718  }
20719  else if(ClpBrdValid == "RlyClpBrd_Cut")
20720  {
20721  PasteMenuItem->Enabled = true;
20722  if(Level1Mode == TrackMode)
20723  {
20724  EditMenu->Enabled = true;
20725  }
20726  CopySelected = false;
20727  Track->CopyFlag = false;
20728 // Level1Mode = TrackMode;
20729  }
20730  }
20731 // end of new section
20732 
20733 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
20734  ClpBrdValid = "";
20735  DeleteMenuItem->Enabled = false;
20736  SelectLengthsMenuItem->Enabled = false;
20737  if(SelectionValid)
20738  {
20739  ReselectMenuItem->Enabled = true;
20740  }
20741  else
20742  {
20743  ReselectMenuItem->Enabled = false;
20744  }
20745  SelectBiDirPrefDirsMenuItem->Visible = false;
20746  CheckPrefDirConflictsMenuItem->Visible = false;
20747  CancelSelectionMenuItem->Enabled = true;
20748  SelectMenuItem->Enabled = true;
20749 
20750  if(NoRailway())
20751  {
20752  SelectMenuItem->Enabled = false;
20753  }
20754  else if(Level1Mode == TrackMode)
20755  {
20756  EditMenu->Enabled = true;
20757  }
20758  Utilities->CallLogPop(2273);
20759 }
20760 
20761 // ---------------------------------------------------------------------------
20762 
20764 {
20765  // no need for caller or log as only setting values
20766  EditMenu->Enabled = true;
20767 
20768  CutMenuItem->Visible = false;
20769  CopyMenuItem->Visible = false;
20770  FlipMenuItem->Visible = false;
20771  MirrorMenuItem->Visible = false;
20772  RotRightMenuItem->Visible = false;
20773  RotLeftMenuItem->Visible = false;
20774  RotateMenuItem->Visible = false;
20775  PasteMenuItem->Visible = false;
20776 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0 (dropped at 2.4.0 as all pastes are with attributes)
20777  DeleteMenuItem->Visible = false;
20778  SelectLengthsMenuItem->Visible = false;
20779  ReselectMenuItem->Visible = false;
20780 
20781  SelectBiDirPrefDirsMenuItem->Visible = true;
20782  CheckPrefDirConflictsMenuItem->Visible = true;
20783  SelectBiDirPrefDirsMenuItem->Enabled = false;
20784  CheckPrefDirConflictsMenuItem->Enabled = true;
20785  CancelSelectionMenuItem->Enabled = true;
20786  SelectMenuItem->Enabled = true;
20787 }
20788 
20789 // ---------------------------------------------------------------------------
20790 
20792 {
20793  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
20794 }
20795 
20796 // ---------------------------------------------------------------------------
20797 
20799 {
20800  SelectRect.left = 0;
20801  SelectRect.right = 0;
20802  SelectRect.top = 0;
20803  SelectRect.bottom = 0;
20804 }
20805 
20806 // ---------------------------------------------------------------------------
20807 
20808 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
20809 {
20810  // return position of erased name in HPos & VPos, return true for found & erased
20811  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
20812  bool TextFound = false;
20813 
20814 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
20815 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
20816  {
20817  if(TextHandler->TextErase(4, HPos, VPos, Name))
20818  {
20819  ;
20820  } // condition not used
20821 
20822  TextFound = true;
20823  }
20824  Utilities->CallLogPop(1956);
20825  return(TextFound);
20826 }
20827 
20828 // ---------------------------------------------------------------------------
20829 
20830 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
20831 {
20832  if(Name == "")
20833  {
20834  return;
20835  }
20836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
20837  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
20838  int VPosHi, VPosLo, TextPosHi, TextPosLo;
20839  TFont *Font = Display->GetFont();
20840 
20841  if(!UseEnteredPosition)
20842  {
20843  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
20844  {
20845  Utilities->CallLogPop(1561);
20846  return;
20847  }
20848  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
20849  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
20850  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
20851  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
20852  int ScreenPosLo = Display->DisplayOffsetV * 16;
20853  if(TextPosLo >= ScreenPosLo)
20854  {
20855  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
20856  }
20857  else if(TextPosHi < ScreenPosHi)
20858  {
20859  VPos = TextPosHi;
20860  }
20861  else
20862  {
20863  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
20864  }
20865  }
20866  TTextItem TI(HPos, VPos, Name, Font);
20867 
20868  TI.Font = Font; // may have been changed in constructor when returned as reference
20869  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
20870  Utilities->CallLogPop(1558);
20871 }
20872 
20873 // ---------------------------------------------------------------------------
20874 
20876 {
20877  try
20878  {
20879 /*
20880  ShowMessage(
20881  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
20882  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
20883  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
20884  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
20885  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
20886  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
20887  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
20888  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
20889  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
20890  "\nInterface->Left " + UnicodeString(Interface->Left) +
20891  "\nInterface->Top " + UnicodeString(Interface->Top) +
20892  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
20893  );
20894 */
20895 /*
20896  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
20897  {
20898  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
20899  {
20900  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
20901  }
20902  }
20903 */
20904 
20905 // throw Exception("Test error"); //generate an error file
20906 
20907 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
20908 
20909  }
20910  catch(const Exception &e)
20911  {
20912  ErrorLog(114, e.Message);
20913  }
20914 }
20915 
20916 // ---------------------------------------------------------------------------
20917 /*
20918  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
20919  {
20920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
20921  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
20922  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
20923  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
20924  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
20925  Utilities->CallLogPop(**);
20926  }
20927 
20928  //---------------------------------------------------------------------------
20929 
20930  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
20931  {
20932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
20933  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
20934  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
20935  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
20936  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
20937  Utilities->CallLogPop(**);
20938  }
20939 */
20940 // ---------------------------------------------------------------------------
20941 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
20942 {
20943  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
20952  Utilities->CallLogPop(1871);
20953 }
20954 
20955 // ---------------------------------------------------------------------------
20956 
20957 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
20958 {
20959  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
20968  Utilities->CallLogPop(1872);
20969 }
20970 
20971 // ---------------------------------------------------------------------------
20972 
20973 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
20974 // limit it to 20 entries max
20975 {
20976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
20978  {
20979  OAListBox->Clear();
20980  }
20982  // new at v2.2.0
20983  {
20984  Utilities->CallLogPop(2092);
20985  return;
20986  }
20987  AnsiString OpTimeToActDisplay;
20988  AnsiString OpTimeToActString;
20989  AnsiString HeadCode;
20990  float OpTimeToActFloat;
20991  TTrainController::THCandTrainPosParam HCandTrainPosParam;
20992 
20995  {
20996  if(OAListBox->Items->Count >= 20)
20997  {
20998  break;
20999  }
21000  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
21001  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
21002  HeadCode = HCandTrainPosParam.first;
21003  if(OpTimeToActFloat < 0.25) // 15 secs estimated
21004  {
21005  OpTimeToActString = "NOW";
21006  }
21007  else if(OpTimeToActFloat < 1)
21008  {
21009  OpTimeToActString = "<1";
21010  }
21011  else
21012  {
21013  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
21014  }
21015  if(OpTimeToActFloat < 60)
21016  {
21017  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
21018  OAListBox->Items->Add(OpTimeToActDisplay); // original
21019  }
21021  }
21022  Utilities->CallLogPop(2093);
21023 }
21024 
21025 // ---------------------------------------------------------------------------
21026 
21027 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
21028 {
21029  try
21030  {
21031  TrainController->LogEvent("LoadUserGraphic");
21032  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
21033  if(LoadUserGraphicDialog->Execute())
21034  {
21035  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
21036  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
21038  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
21039  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
21040  {
21041  UGME.first = SelectedGraphicFileName;
21042  TPicture *PicPtr = new TPicture;
21043  PicPtr->LoadFromFile(SelectedGraphicFileName);
21044  UGME.second = PicPtr;
21045  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
21046  {
21047  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
21048  }
21049  }
21051  SetLevel2TrackMode(65);
21052  }
21053  Utilities->CallLogPop(2191);
21054  }
21055  catch(const EInvalidGraphic &e) //non error catch
21056  {
21057  ShowMessage(
21058  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
21059  Utilities->CallLogPop(2311);
21060  }
21061  catch(const Exception &e)
21062  {
21063  ErrorLog(215, e.Message);
21064  }
21065 }
21066 
21067 // ---------------------------------------------------------------------------
21068 
21069 void TInterface::LoadClipboard(int Caller) // new at v2.8.0
21070 {
21071  try
21072  {
21073  TrainController->LogEvent("LoadClipboard");
21074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadClipboard");
21075 
21076  std::wstringstream wss; // used to hold all parameters prior to conversion to a string buffer
21077  if(CopySelected)
21078  {
21079  wss << "RlyClpBrdCopy\n";
21080  }
21081  else
21082  {
21083  wss << "RlyClpBrd_Cut\n";
21084  }
21085 // Load the active & inactive track vectors
21086  for(TTrack::TTrackVectorIterator TTVIt = Track->SelectVector.begin(); TTVIt < Track->SelectVector.end(); TTVIt++)
21087  {
21088  wss << TTVIt->SpeedTag;
21089  wss << '\n'; // inherited int - all FixedTrackPiece parameters implicit in this
21090  for(int AnsLen = 0; AnsLen <= TTVIt->ActiveTrackElementName.Length(); AnsLen++)
21091  {
21092  if((TTVIt->ActiveTrackElementName).c_str()[AnsLen] != '\0')
21093  {
21094  wss << (TTVIt->ActiveTrackElementName).c_str()[AnsLen];
21095  }
21096  else
21097  {
21098  wss << '\n';
21099  }
21100  }
21101  for(int AnsLen = 0; AnsLen <= TTVIt->ElementID.Length(); AnsLen++)
21102  {
21103  if((TTVIt->ElementID).c_str()[AnsLen] != '\0')
21104  {
21105  wss << (TTVIt->ElementID).c_str()[AnsLen];
21106  }
21107  else
21108  {
21109  wss << '\n';
21110  }
21111  }
21112  for(int AnsLen = 0; AnsLen <= TTVIt->LocationName.Length(); AnsLen++)
21113  {
21114  if((TTVIt->LocationName).c_str()[AnsLen] != '\0')
21115  {
21116  wss << (TTVIt->LocationName).c_str()[AnsLen];
21117  }
21118  else
21119  {
21120  wss << '\n';
21121  }
21122  }
21123  wss << TTVIt->CallingOnSet;
21124  wss << '\n';
21125  wss << TTVIt->LCPlotted;
21126  wss << '\n';
21127  wss << TTVIt->TempTrackMarker01;
21128  wss << '\n';
21129  wss << TTVIt->TempTrackMarker23;
21130  wss << '\n';
21131  wss << TTVIt->Attribute;
21132  wss << '\n'; // all ints from here except last which is an enum
21133  wss << TTVIt->Conn[0];
21134  wss << '\n';
21135  wss << TTVIt->Conn[1];
21136  wss << '\n';
21137  wss << TTVIt->Conn[2];
21138  wss << '\n';
21139  wss << TTVIt->Conn[3];
21140  wss << '\n';
21141  wss << TTVIt->ConnLinkPos[0];
21142  wss << '\n';
21143  wss << TTVIt->ConnLinkPos[1];
21144  wss << '\n';
21145  wss << TTVIt->ConnLinkPos[2];
21146  wss << '\n';
21147  wss << TTVIt->ConnLinkPos[3];
21148  wss << '\n';
21149  wss << TTVIt->HLoc;
21150  wss << '\n';
21151  wss << TTVIt->VLoc;
21152  wss << '\n';
21153  wss << TTVIt->Length01;
21154  wss << '\n';
21155  wss << TTVIt->Length23;
21156  wss << '\n';
21157  wss << TTVIt->SpeedLimit01;
21158  wss << '\n';
21159  wss << TTVIt->SpeedLimit23;
21160  wss << '\n';
21161  wss << TTVIt->StationEntryStopLinkPos1;
21162  wss << '\n';
21163  wss << TTVIt->StationEntryStopLinkPos2;
21164  wss << '\n';
21165  wss << TTVIt->TrainIDOnElement;
21166  wss << '\n';
21167  wss << TTVIt->TrainIDOnBridgeTrackPos01;
21168  wss << '\n';
21169  wss << TTVIt->TrainIDOnBridgeTrackPos23;
21170  wss << '\n';
21171  wss << int(TTVIt->SigAspect);
21172  wss << '\n'; // enum
21173  }
21174  wss << "$$$" << '\n'; // send track element end marker
21175 
21176 // Load the text vector
21177 
21178  for(TTextHandler::TTextVectorIterator TTVIt = TextHandler->SelectTextVector.begin(); TTVIt < TextHandler->SelectTextVector.end(); TTVIt++)
21179  {
21180  for(int AnsLen = 0; AnsLen <= TTVIt->TextString.Length(); AnsLen++)
21181  {
21182  if((TTVIt->TextString).c_str()[AnsLen] != '\0')
21183  {
21184  wss << (TTVIt->TextString).c_str()[AnsLen];
21185  }
21186  else
21187  {
21188  wss << '\n';
21189  }
21190  }
21191  wss << TTVIt->HPos;
21192  wss << '\n';
21193  wss << TTVIt->VPos;
21194  wss << '\n';
21195  for(int AnsLen = 0; AnsLen <= AnsiString(TTVIt->Font->Name).Length(); AnsLen++)
21196  {
21197  if(AnsiString(TTVIt->Font->Name).c_str()[AnsLen] != '\0')
21198  {
21199  wss << AnsiString(TTVIt->Font->Name).c_str()[AnsLen];
21200  }
21201  else
21202  {
21203  wss << '\n';
21204  }
21205  }
21206  wss << TTVIt->Font->Size;
21207  wss << '\n';
21208  if((TTVIt->Font->Color < 0) || (TTVIt->Font->Color > 0xFFFFFF)) // if set to any of the special 'windows' colours save it as black
21209  {
21210  wss << "0\n";
21211  }
21212  else
21213  {
21214  wss << int(TTVIt->Font->Color) << '\n';
21215  }
21216  wss << int(TTVIt->Font->Charset) << '\n'; // save as 'int' (would be unsigned char else) so 'n' can act as proper delimiter
21217  wss << TextHandler->GetFontStyleAsInt(1, TTVIt->Font) << '\n';
21218  }
21219  wss << "$$$" << '\n'; // send text item end marker
21220 
21221  //load select dimensions
21222  wss << SelectBitmap->Height;
21223  wss << '\n';
21224  wss << SelectBitmap->Width;
21225  wss << '\n';
21226  wss << SelectRect.left;
21227  wss << '\n';
21228  wss << SelectRect.top;
21229  wss << '\n';
21230  wss << "$$$" << '\n'; // send end of select dimension marker
21231 
21232  //load preferred directions //added at v2.9.0
21233  if(SelectPrefDir->PrefDirSize() > 0) // skip load if empty
21234  {
21235  for(TOnePrefDir::TPrefDirVectorIterator PDVIt = SelectPrefDir->PrefDirVector.begin(); PDVIt < SelectPrefDir->PrefDirVector.end(); PDVIt++)
21236  {
21237  //Note that TrackVector Position won't be valid for a remote paste, it will be reset when pasted, also Conns & ConnLinkPosses set when
21238  //track linked
21239  wss << PDVIt->GetTrackVectorPosition(); //added at v2.9.2 so all 9 of CheckCount properties loaded (SpeedTag loaded from TrackElement at HLoc & VLoc)
21240  wss << '\n';
21241  wss << PDVIt->GetHLoc();
21242  wss << '\n';
21243  wss << PDVIt->GetVLoc();
21244  wss << '\n';
21245  wss << PDVIt->GetELink();
21246  wss << '\n';
21247  wss << PDVIt->GetELinkPos();
21248  wss << '\n';
21249  wss << PDVIt->GetXLink();
21250  wss << '\n';
21251  wss << PDVIt->GetXLinkPos();
21252  wss << '\n';
21253  wss << PDVIt->GetEXNumber();
21254  wss << '\n';
21255  }
21256  }
21257  wss << "$$$" << '\n'; // send pref dir end marker
21258  wss << '\0'; // has to end with NULL
21259 
21260  Clipboard()->Clear(); // clear the clipboard
21261  Clipboard()->SetTextBuf(&(wss.str()[0])); // populate the clipboard
21262  Clipboard()->Close();
21263 
21264  Utilities->CallLogPop(2267);
21265  }
21266 
21267  catch(const EClipboardException &e) // ignore access denials (but only seems to happen with recover), doesn't affect program //non error catch
21268  {
21269 // Application->MessageBox(L"A clipboard error occurred in loading the clipboard", L"Message", MB_OK);
21270  Utilities->CallLogPop(2312);
21271  }
21272 
21273  catch(const Exception &e)
21274  {
21275  ErrorLog(222, e.Message);
21276  }
21277 
21278 }
21279 
21280 // ---------------------------------------------------------------------------
21281 
21282 void TInterface::RecoverClipboard(int Caller, bool &ValidResult) // new at v2.8.0
21283 {
21284  try
21285  {
21286  TrainController->LogEvent("RecoverClipboard");
21287  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RecoverClipboard");
21288  ValidResult = false;
21289  System::WideChar *SelectVectorBuffer = new System::WideChar[4000000]; // scope for 130 chars per element & 4k resolution (240 x 135 elements)
21290  int StreamSize = 0;
21291  StreamSize = Clipboard()->GetTextBuf(SelectVectorBuffer, 4000000);
21292  Clipboard()->Clear(); // clear it so can't keep pasting same thing as don't permit this in single app
21293  Clipboard()->Close();
21294  if(StreamSize < 14)
21295  {
21296  Utilities->CallLogPop(2270); // ValidResult == false
21297  return;
21298  }
21299  std::wstringstream wss;
21300  wss << SelectVectorBuffer;
21301  ClpBrdValid = AnsiString(SelectVectorBuffer).SubString(1, 13);
21302  PasteMenuItem->Enabled = false;
21303  delete[]SelectVectorBuffer;
21304 
21305  if((ClpBrdValid != AnsiString("RlyClpBrdCopy")) && (ClpBrdValid != AnsiString("RlyClpBrd_Cut")))
21306  {
21307  Utilities->CallLogPop(2268); // ValidResult == false
21308  return;
21309  }
21310  int MarkerCounter = 0; //If ever get a MarkerCounter value well outside expected range it's probably because some text is too long - see comment below
21311  ClpBrdValid = "";
21312  wchar_t LineString[1000]; // should be big enough for any entry, (extended from 100 at v2.9.2) text can be long but hopefully not this long - won't
21313  //recover the clipboard if longer but won't crash. It has to be at least as big as the biggest getline number or the excess will overwrite other variables,
21314  //this was discovered when MarkerCounter suddenly jumped from 1 to nearly 3000000 when Linesting loaded with text ~180 chars long with LineString limited
21315  //to 100 chars
21316 
21317  wss.getline(LineString, 100); // RlyClpBrdCopy or ...Cut - discard it
21318  Track->SelectVector.clear();
21319  TTrack::TTrackMap SelectTrackMap; //build map so can find TrackElement at required H & V to build PrefDirElement from it //added at v2.9.0
21320  THVPair SelectTrackMapKeyPair; //for above
21321  TTrack::TTrackMapEntry SelectTrackMapEntry; //for above
21322  while(true) // recover active & inactive track (active first & top to bottom at leftmost position then again stepping right
21323  {
21324  wss.getline(LineString, 100);
21325  if(AnsiString(LineString) == "$$$") // end of track element marker
21326  {
21327  MarkerCounter++;
21328  break;
21329  }
21330  // if not $$$ then it's the SpeedTag number
21331  TTrackElement TE = Track->BuildBasicElementFromSpeedTag(5, AnsiString(LineString).ToInt());
21332  wss.getline(LineString, 100);
21333  TE.ActiveTrackElementName = AnsiString(LineString); // if not "$$$" must be the start of the next element
21334  wss.getline(LineString, 100);
21335  TE.ElementID = AnsiString(LineString);
21336  wss.getline(LineString, 100);
21337  TE.LocationName = AnsiString(LineString);
21338 
21339  wss.getline(LineString, 100);
21340  TE.CallingOnSet = AnsiString(LineString).ToInt();
21341  wss.getline(LineString, 100);
21342  TE.LCPlotted = AnsiString(LineString).ToInt();
21343  wss.getline(LineString, 100);
21344  TE.TempTrackMarker01 = AnsiString(LineString).ToInt();
21345  wss.getline(LineString, 100);
21346  TE.TempTrackMarker23 = AnsiString(LineString).ToInt();
21347 
21348  wss.getline(LineString, 100);
21349  TE.Attribute = AnsiString(LineString).ToInt();
21350  wss.getline(LineString, 100);
21351  TE.Conn[0] = AnsiString(LineString).ToInt();
21352  wss.getline(LineString, 100);
21353  TE.Conn[1] = AnsiString(LineString).ToInt();
21354  wss.getline(LineString, 100);
21355  TE.Conn[2] = AnsiString(LineString).ToInt();
21356  wss.getline(LineString, 100);
21357  TE.Conn[3] = AnsiString(LineString).ToInt();
21358  wss.getline(LineString, 100);
21359  TE.ConnLinkPos[0] = AnsiString(LineString).ToInt();
21360  wss.getline(LineString, 100);
21361  TE.ConnLinkPos[1] = AnsiString(LineString).ToInt();
21362  wss.getline(LineString, 100);
21363  TE.ConnLinkPos[2] = AnsiString(LineString).ToInt();
21364  wss.getline(LineString, 100);
21365  TE.ConnLinkPos[3] = AnsiString(LineString).ToInt();
21366  wss.getline(LineString, 100);
21367  TE.HLoc = AnsiString(LineString).ToInt();
21368  wss.getline(LineString, 100);
21369  TE.VLoc = AnsiString(LineString).ToInt();
21370  wss.getline(LineString, 100);
21371  TE.Length01 = AnsiString(LineString).ToInt();
21372  wss.getline(LineString, 100);
21373  TE.Length23 = AnsiString(LineString).ToInt();
21374  wss.getline(LineString, 100);
21375  TE.SpeedLimit01 = AnsiString(LineString).ToInt();
21376  wss.getline(LineString, 100);
21377  TE.SpeedLimit23 = AnsiString(LineString).ToInt();
21378  wss.getline(LineString, 100);
21379  TE.StationEntryStopLinkPos1 = AnsiString(LineString).ToInt();
21380  wss.getline(LineString, 100);
21381  TE.StationEntryStopLinkPos2 = AnsiString(LineString).ToInt();
21382  wss.getline(LineString, 100);
21383  TE.TrainIDOnElement = AnsiString(LineString).ToInt();
21384  wss.getline(LineString, 100);
21385  TE.TrainIDOnBridgeTrackPos01 = AnsiString(LineString).ToInt();
21386  wss.getline(LineString, 100);
21387  TE.TrainIDOnBridgeTrackPos23 = AnsiString(LineString).ToInt();
21388 
21389  wss.getline(LineString, 100);
21390  int temp = AnsiString(LineString).ToInt();
21391  if(temp == 0)
21392  {
21394  }
21395  else if(temp == 1)
21396  {
21398  }
21399  else if(temp == 2)
21400  {
21402  }
21403  else if(temp == 3)
21404  {
21406  }
21407  Track->SelectVector.push_back(TE);
21408  if((TE.TrackType != Concourse) && (TE.TrackType != Parapet) && (TE.TrackType != NamedNonStationLocation) && (TE.TrackType != Platform)
21409  && (TE.TrackType != LevelCrossing)) //aded at v2.9.2 so only active elements added to SelectTrackMap
21410  {
21411  SelectTrackMapKeyPair.first = TE.HLoc;
21412  SelectTrackMapKeyPair.second = TE.VLoc;
21413  SelectTrackMapEntry.first = SelectTrackMapKeyPair;
21414  SelectTrackMapEntry.second = Track->SelectVector.size() - 1;
21415  SelectTrackMap.insert(SelectTrackMapEntry);
21416  }
21417  }
21418 
21419  TextHandler->SelectTextVector.clear();
21420  AnsiString FontName;
21421  int FontSize, FontColour, FontCharset, FontStyle;
21422  while(true) // recover text
21423  {
21424  wss.getline(LineString, 1000);
21425  if(AnsiString(LineString) == "$$$") // end of text marker
21426  {
21427  MarkerCounter++;
21428  break;
21429  }
21430  // if not $$$ then it's the text string
21431  TTextItem TI;
21432  TI.TextString = AnsiString(LineString);
21433  wss.getline(LineString, 1000); //extended to 1000 from 100 for text items at v2.9.2
21434  TI.HPos = AnsiString(LineString).ToInt();
21435  wss.getline(LineString, 1000);
21436  TI.VPos = AnsiString(LineString).ToInt();
21437  wss.getline(LineString, 1000);
21438  FontName = AnsiString(LineString).c_str();
21439  wss.getline(LineString, 1000);
21440  FontSize = AnsiString(LineString).ToInt();
21441  wss.getline(LineString, 1000);
21442  FontColour = AnsiString(LineString).ToInt();
21443  wss.getline(LineString, 1000);
21444  FontCharset = AnsiString(LineString).ToInt();
21445  wss.getline(LineString, 1000);
21446  FontStyle = AnsiString(LineString).ToInt();
21447  // create a new font
21448  TFont *NewFont = new TFont;
21449  NewFont->Name = FontName;
21450  NewFont->Size = FontSize;
21451  NewFont->Color = static_cast<TColor>(FontColour);
21452  NewFont->Charset = FontCharset;
21453  NewFont->Style = TextHandler->SetFontStyleFromInt(1, FontStyle);
21454  TI.Font = NewFont;
21455  TextHandler->SelectTextVector.push_back(TI);
21456  }
21457 
21458  // recover select dimensions
21459  wss.getline(LineString, 100);
21460  SelectBitmap->Height = AnsiString(LineString).ToInt();
21461  wss.getline(LineString, 100);
21462  SelectBitmap->Width = AnsiString(LineString).ToInt();
21463  wss.getline(LineString, 100);
21464  SelectRect.left = AnsiString(LineString).ToInt();
21465  wss.getline(LineString, 100);
21466  SelectRect.top = AnsiString(LineString).ToInt();
21467  wss.getline(LineString, 100);
21468  if(AnsiString(LineString) == "$$$")
21469  {
21470  MarkerCounter++;
21471  }
21472 
21473  // recover pref dirs - after dimensions so that a clipboard loaded with this app will paste into an earlier version app without pref dirs
21474  // if a clipboard loaded with an earlier app is pasted into this app then the marker will be wrong, an error message will be given but no crash
21475  int TempTVPos, TempHLoc, TempVLoc, TempELink, TempELinkPos, TempXLink, TempXLinkPos, TempEXNumber, ATVecPos;
21476  bool FoundFlag;
21478  while(true)
21479  {
21480  wss.getline(LineString, 100);
21481  if(AnsiString(LineString) == "$$$") // end of pref dir element marker
21482  {
21483  MarkerCounter++;
21484  break;
21485  }
21486  // if not $$$ then it's the TVPos value
21487  TempTVPos = AnsiString(LineString).ToInt(); //added at v2.9.2 so all 9 CheckCount properties valid (SpeedTag loaded from corresponding TrackElement)
21488  wss.getline(LineString, 100);
21489  TempHLoc = AnsiString(LineString).ToInt();
21490  wss.getline(LineString, 100);
21491  TempVLoc = AnsiString(LineString).ToInt();
21492  wss.getline(LineString, 100);
21493  TempELink = AnsiString(LineString).ToInt();
21494  wss.getline(LineString, 100);
21495  TempELinkPos = AnsiString(LineString).ToInt();
21496  wss.getline(LineString, 100);
21497  TempXLink = AnsiString(LineString).ToInt();
21498  wss.getline(LineString, 100);
21499  TempXLinkPos = AnsiString(LineString).ToInt();
21500  wss.getline(LineString, 100);
21501  TempEXNumber = AnsiString(LineString).ToInt();
21502  //build a pref dir element from these values and the corresponding TrackVectorPosition for HLoc & VLoc
21503  TTrackElement TempElement = Track->GetTrackElementFromAnyTrackMap(0, TempHLoc, TempVLoc, SelectTrackMap, Track->SelectVector);
21504  TPrefDirElement TempPrefDirElement(TempElement);
21505 // TempPrefDirElement.HLoc = TempHLoc; //these and SpeedTag already set from TempElement
21506 // TempPrefDirElement.VLoc = TempVLoc;
21507  TempPrefDirElement.SetTrackVectorPosition(TempTVPos); //added at v2.9.2 so all 9 CheckCount properties have values (SpeedTag loaded from corresponding TrackElement)
21508  //TVPos only included for completeness & not valid yet, it will change to the correct value when pasted
21509  //and change again when the track is linked
21510  TempPrefDirElement.SetELink(TempELink);
21511  TempPrefDirElement.SetELinkPos(TempELinkPos);
21512  TempPrefDirElement.SetXLink(TempXLink);
21513  TempPrefDirElement.SetXLinkPos(TempXLinkPos);
21514  TempPrefDirElement.SetEXNumber(TempEXNumber);
21515  TempPrefDirElement.SetCheckCount(9); //added at v2.9.2
21516  SelectPrefDir->ExternalStorePrefDirElement(11, TempPrefDirElement); //added 27/05 at v2.9.0
21517  }
21518 
21519  if(MarkerCounter == 4)
21520  {
21521  ValidResult = true;
21522  }
21523  Utilities->CallLogPop(2269);
21524  }
21525 
21526  catch(const Exception &e) //don't stop for any error in this section, just give bad clipboard message //non error catch
21527  {
21528  ValidResult = false;
21529  Utilities->CallLogPop(2313);
21530 // ErrorLog(223, e.Message);
21531  }
21532 
21533 }
21534 
21535 // ---------------------------------------------------------------------------
21536 
21537 /*
21538  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
21539 
21540  These problems were with Borland C++Builder 4.
21541 
21542  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
21543  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
21544  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
21545  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
21546  clear what was special about this particular string.
21547  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
21548  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
21549  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
21550  This is thought to be a flaw in the compiler.
21551  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
21552  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
21553  read a null, even though the pointer had been reset to its value before the call to
21554  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
21555  that is indicated by tellg and the true pointer within the system can be different.
21556  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
21557  used for both with the new library just defined within the std namespace.
21558  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
21559  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
21560  (note - don't need the ifstream file to be open in output mode for the putback to work)
21561  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
21562  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
21563  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
21564  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
21565  file and that read by the program.
21566  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
21567  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
21568  'Frh' at the end of the entry following that for the earlier sticking point. Here
21569  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
21570  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
21571  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
21572  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
21573  would tally, though would still be wrong.
21574  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
21575  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
21576  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
21577  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
21578  lines are only separated by single newline characters.
21579 
21580  Need to check:
21581  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
21582  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
21583  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
21584 
21585  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
21586  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
21587  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
21588  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
21589 
21590  For 2: Works OK using getline().
21591 
21592  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
21593  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
21594  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
21595  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
21596 
21597  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
21598 */
21599 
21600 // ---------------------------------------------------------------------------
21601 
21602 
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17470
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:565
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3850
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:956
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:483
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11241
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9041
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:419
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:347
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1137
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:863
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:314
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:646
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:313
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TPrefDirElement::SetEXGraphicPtr
void SetEXGraphicPtr(Graphics::TBitmap *input)
Used in pasting pref dirs.
Definition: TrackUnit.h:382
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11214
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:116
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:470
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:280
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:92
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2803
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:646
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:446
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:540
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1059
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13994
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:205
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:19247
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:548
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1113
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:361
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:307
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12760
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13784
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:863
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1700
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:201
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:342
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13365
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:105
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:649
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:465
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:335
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:18495
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:754
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:468
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:808
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:93
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:51
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:469
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4359
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:13637
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:576
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:650
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:538
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4320
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1111
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:202
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:270
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:50
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1099
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:560
TInterface::PasteWarningSentFlag
bool PasteWarningSentFlag
indicates that the warning message about pasting overwriting the area has been given,...
Definition: InterfaceUnit.h:986
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1123
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:312
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:353
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:197
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:809
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1050
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12800
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3217
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1065
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10739
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3625
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:876
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:1044
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:1018
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:20075
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2132
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:266
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:393
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:343
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:881
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:792
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:299
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1053
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7061
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:51
TTrainController::LastSessionSaveTTClockTime
TDateTime LastSessionSaveTTClockTime
Definition: TrainUnit.h:657
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:937
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1629
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:525
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5533
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6962
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5560
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:119
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:8297
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:776
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:287
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:573
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:434
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:626
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1085
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:429
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1909
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:341
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10140
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:18006
TInterface::ClpBrdValid
AnsiString ClpBrdValid
set to RlyClpBrdCopy or RlyClpBrd_Cut when Windows Clipboard contains a valid railway segment
Definition: InterfaceUnit.h:913
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:397
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:558
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:878
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:1012
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:491
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12730
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:625
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2733
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:622
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5713
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:152
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:335
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1097
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:895
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:72
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7980
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:431
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:379
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:663
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:20798
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:1020
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:349
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:308
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:740
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:229
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12539
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:277
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:355
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:1042
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7447
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:146
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9286
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:596
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:335
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:823
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:740
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1816
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9407
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:641
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:617
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:998
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:297
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:12883
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13829
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14892
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:20941
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:7480
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:350
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:137
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:514
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1139
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:128
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17430
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:378
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18266
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:1004
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:142
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2151
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:427
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:16183
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:740
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:18511
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:508
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:8313
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:944
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:19948
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:466
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:159
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:100
TInterface::SigPrefConsecButtonClick
void __fastcall SigPrefConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2216
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3571
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4355
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:885
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:14907
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:547
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:447
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1051
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:885
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3373
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11261
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:863
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9225
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3550
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:453
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:20957
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:242
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:399
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1117
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1444
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:553
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12642
NotStarted
@ NotStarted
Definition: TrainUnit.h:86
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4515
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:804
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2295
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:417
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6245
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1063
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1049
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13932
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:931
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:874
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3447
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:245
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12025
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:792
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:132
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:645
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:509
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:315
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1307
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:15865
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:64
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:343
TTrainDataEntry
Contains all data for a single train.
Definition: TrainUnit.h:184
TPrefDirElement::SetXLinkPos
void SetXLinkPos(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:370
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:783
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18740
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5690
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:535
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:541
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9163
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:18935
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9351
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:183
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2113
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:20088
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:6264
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:113
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:449
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1522
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1608
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5756
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:471
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:602
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13384
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:296
TTextHandler::GetFontStyleAsInt
int GetFontStyleAsInt(int Caller, TFont *InputFont)
retrieve the style of the font as a coded integer
Definition: TextUnit.cpp:99
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1437
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TInterface::SetTrackModeEditMenu
void SetTrackModeEditMenu(int Caller)
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:20675
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:676
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2710
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:531
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:459
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1012
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:15010
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3171
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:278
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15415
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4893
TInterface::ClipboardChecked
bool ClipboardChecked
used to prevent Windows clipboard beng checked repeatedly
Definition: InterfaceUnit.h:948
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:15869
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:14583
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:14420
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1180
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:14948
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:632
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:50
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12605
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:796
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:316
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:440
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2782
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13949
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11465
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1074
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4822
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1061
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:884
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:950
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1375
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12856
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5673
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:463
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1651
TTrain
Definition: TrainUnit.h:279
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:298
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:10587
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:154
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11255
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:263
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1108
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:94
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:644
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:1000
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:816
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7462
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:579
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:344
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:440
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1067
GapJump
@ GapJump
Definition: TrackUnit.h:67
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:284
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:119
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:568
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:564
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:786
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:935
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:863
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:467
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7208
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:150
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:521
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13244
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:150
TTrack::IsReadyForOperation
bool IsReadyForOperation(bool GiveMessage)
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:829
TTrack::Raising
@ Raising
Definition: TrackUnit.h:625
TInterface::OAListBoxRightMouseButtonDown
bool OAListBoxRightMouseButtonDown
flag set when right mouse button clicked over op action list box, so floating information window show...
Definition: InterfaceUnit.h:984
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:9005
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:584
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10245
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:335
TTrackElement::TempTrackMarker23
bool TempTrackMarker23
Utility markers for program use.
Definition: TrackUnit.h:140
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:511
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1219
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:493
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1668
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12710
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:335
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:20056
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:921
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4850
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:198
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:532
TPrefDirElement::SetELink
void SetELink(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:352
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:253
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1101
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:329
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:202
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:649
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:254
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:17819
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:581
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:14989
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:960
TPrefDirElement::GetXLink
int GetXLink() const
Returns XLink.
Definition: TrackUnit.h:293
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:779
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:298
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:359
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:422
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:896
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:640
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:441
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1384
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:578
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:144
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5905
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1528
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9636
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:200
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:879
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:14332
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:365
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6845
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:636
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:310
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:561
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:387
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:129
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:543
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:16240
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:20830
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10354
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:366
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13716
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:317
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:884
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:15072
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5614
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:895
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:395
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:121
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:804
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:126
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:380
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:581
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3738
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:990
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:991
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:860
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:791
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:67
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:186
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:901
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:387
TTrainController::EarlyExits
int EarlyExits
Definition: TrainUnit.h:780
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9316
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:426
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17418
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:520
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:374
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1871
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12129
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:135
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:19079
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1057
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4020
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7476
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages, bool &TwoLocationFlag)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:11631
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6654
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1143
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1121
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:599
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:625
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:939
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8640
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:317
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13213
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:874
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17403
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:264
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:63
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:392
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12700
TInterface::LoadClipboard
void LoadClipboard(int Caller)
Load system clipboard to allow cutting & pasting between separate railway applications.
Definition: InterfaceUnit.cpp:21069
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:793
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:281
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:384
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1046
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:813
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2640
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1981
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:385
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1141
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11746
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:433
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13470
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:14368
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:890
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:436
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1048
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:789
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:413
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1136
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:754
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4440
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:255
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1859
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:130
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:397
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:582
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:440
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:651
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:890
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:594
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:787
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4537
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:401
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1058
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:534
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1688
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:180
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:194
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11561
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:778
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:113
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:440
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:1014
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:416
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:448
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:567
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:627
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:9905
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2693
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:642
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1156
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:276
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:335
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:1008
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:159
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:382
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1878
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:376
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:740
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:896
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:368
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:450
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1423
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:543
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:863
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12904
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:670
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11073
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:437
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1167
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:771
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:301
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:507
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:824
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:20568
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5960
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1534
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11651
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:895
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8437
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:835
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1716
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1060
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1692
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:18028
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5584
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1694
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:516
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:292
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:609
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1310
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:860
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:766
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5879
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:12944
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:1016
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12079
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:591
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10607
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7873
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:20313
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1698
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9896
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:198
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1103
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:611
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:589
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6701
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:757
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12572
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1780
TInterface::LengthWarningSentFlag
bool LengthWarningSentFlag
indicates that the length selection applying to all elements in the selection warning has been given,...
Definition: InterfaceUnit.h:970
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:637
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9657
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:451
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:942
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3548
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:68
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:607
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:428
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2489
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11116
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:70
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1110
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4875
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2390
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1761
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13461
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:600
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13289
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1106
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:551
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13060
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:933
TInterface::FillSelectionMessageSentFlag
bool FillSelectionMessageSentFlag
indicates that the message about filling a selected area with a chosen track element has been given,...
Definition: InterfaceUnit.h:966
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2008
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:365
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:925
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:647
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:1036
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:869
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:630
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:399
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1009
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12392
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:522
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:356
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:428
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:52
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:813
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:640
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:337
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11267
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:138
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:764
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3767
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:445
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11335
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:719
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:90
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:648
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:199
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:136
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:351
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4383
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:563
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1078
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:489
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5632
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1795
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13308
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13408
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:240
TInterface::LCManualLowerBarriersMessageSent
bool LCManualLowerBarriersMessageSent
indicates that the manual LC operation message has been given, so it won't be given again
Definition: InterfaceUnit.h:968
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2901
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:141
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:52
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:879
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:554
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:566
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5733
TInterface::RecoverClipboard
void RecoverClipboard(int Caller, bool &ValidResult)
Recovers clipboard as track and text vectors.
Definition: InterfaceUnit.cpp:21282
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3764
TTrainController::LateExits
int LateExits
Definition: TrainUnit.h:785
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
<List of all ServiceRefs that have two or more same locations without a cdt between - loaded during S...
Definition: TrainUnit.h:808
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:349
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5244
TInterface::CopySelected
bool CopySelected
used to indicate whether copy or cut selected in edit menu - for clipboard pasting
Definition: InterfaceUnit.h:954
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1162
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:12036
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:19869
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14011
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12671
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:895
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:14612
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9479
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:297
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:498
TInterface::TwoLocationNamePanelHide
bool TwoLocationNamePanelHide
true if user opts not to show the two location name warning (false on starting the program)
Definition: InterfaceUnit.h:1022
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:896
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:770
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:325
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1110
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4969
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:15225
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:614
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1484
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8404
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:19924
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1639
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:440
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17257
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1628
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:341
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:352
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:200
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:196
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:777
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:140
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:592
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:628
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6112
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:610
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:480
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1047
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7117
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9779
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:478
AtLocation
@ AtLocation
Definition: TrainUnit.h:70
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:148
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:77
TPrefDirElement::GetSignedIntTrackVectorPosition
int GetSignedIntTrackVectorPosition() const
Returns signed integer value of TrackVectorPosition (used in flip, mirror etc for pref dirs) added at...
Definition: TrackUnit.h:323
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:1030
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:18872
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:785
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17707
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:154
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:462
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:822
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12442
TAllRoutes::NotAutoSigsRoute
@ NotAutoSigsRoute
Definition: TrackUnit.h:1629
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:422
TPrefDirElement::SetEntryDirectionGraphicPtr
void SetEntryDirectionGraphicPtr(Graphics::TBitmap *input)
Used in pasting pref dirs.
Definition: TrackUnit.h:388
Exited
@ Exited
Definition: TrainUnit.h:86
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:295
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:230
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:580
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9102
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:386
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11789
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:17680
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:556
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10340
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:14923
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:537
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:1028
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2341
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:597
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1119
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:619
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:588
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:569
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:638
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:790
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:17047
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:250
TInterface::CheckPrefDirConflictsMenuItem
TMenuItem * CheckPrefDirConflictsMenuItem
Definition: InterfaceUnit.h:444
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:440
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:700
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13346
TInterface::OAListBoxMouseDown
void __fastcall OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5026
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:422
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:457
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:742
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:20791
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:406
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9010
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:497
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2085
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:4065
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1696
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:1038
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:372
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:522
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4475
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:181
TInterface::CheckPrefDirConflictsMenuItemClick
void __fastcall CheckPrefDirConflictsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10780
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:754
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13521
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:323
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:549
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14238
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:335
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:17930
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4043
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:895
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2340
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:795
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11199
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:13128
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12210
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:294
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:363
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:590
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:583
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:634
TInterface::GetTrainFloatingInfoFromContinuation
void GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat, AnsiString &TrainTTFloat)
Called when floating train info needed and train hasn't entered yet.
Definition: InterfaceUnit.cpp:16681
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:952
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5608
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:175
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18908
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:218
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:101
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11502
TTrack::Down
@ Down
Definition: TrackUnit.h:625
TTrainController::TwoOrMoreLocationsWarningGiven
bool TwoOrMoreLocationsWarningGiven
new at v2.6.0 to allow loops
Definition: TrainUnit.h:750
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:313
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:585
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:112
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:557
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:17762
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:64
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1515
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:1034
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6815
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:912
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:598
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10626
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:440
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:233
TInterface::MMoveTextGraphicUserGraphicFoundFlag
bool MMoveTextGraphicUserGraphicFoundFlag
Mouse move flags to prevent repeated event logs.
Definition: InterfaceUnit.h:980
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:504
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:204
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12993
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17349
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:673
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7190
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:14972
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12761
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:406
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:19893
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:82
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:521
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
TInterface::TooLongMessageSentFlag
bool TooLongMessageSentFlag
indicates that the length of a location element might be too long (>200m), so it won't be given again
Definition: InterfaceUnit.h:1024
Timetable
@ Timetable
Definition: TrainUnit.h:58
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TInterface
Definition: InterfaceUnit.h:56
TTextHandler::SetFontStyleFromInt
TFontStyles SetFontStyleFromInt(int Caller, int Input)
used in loading from a file
Definition: TextUnit.cpp:126
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11836
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10035
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6756
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:748
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:18450
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:632
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5804
Parapet
@ Parapet
Definition: TrackUnit.h:68
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:776
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17376
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1076
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:510
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:740
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:287
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8921
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17322
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:521
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:401
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:746
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:813
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:754
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:788
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:440
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:550
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:148
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:249
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:454
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:408
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:338
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:145
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:370
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:569
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:523
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1156
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:559
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:613
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:15248
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9507
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:138
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12137
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:421
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:618
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13852
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1180
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:501
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12690
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1056
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:796
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:919
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12740
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1158
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:732
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:512
TTrack
Definition: TrackUnit.h:562
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5897
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:860
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:426
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:73
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:389
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:484
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1378
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1081
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:992
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:463
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:896
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:66
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:412
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:265
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
new at v2.4.0, resets after 53 seconds (53 prime so can trigger at any clock time)
Definition: TrainUnit.h:812
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:629
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:880
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:974
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:621
TTrainController::TwoLocationList
TServiceCallingLocsList TwoLocationList
Definition: TrainUnit.h:806
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:866
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:219
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:280
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1145
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:69
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:567
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:549
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:129
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:45
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1165
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:587
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:282
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:895
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2885
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:14095
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5568
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:423
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5660
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8717
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1156
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4636
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4249
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:788
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:472
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:931
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1702
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:513
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:754
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:363
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2092
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3366
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:416
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:575
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12681
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:257
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:530
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:1040
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1177
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5918
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:422
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:159
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:796
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1087
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2558
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:111
TInterface::MMoveTextGraphicTextFoundFlag
bool MMoveTextGraphicTextFoundFlag
Definition: InterfaceUnit.h:979
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:52
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:901
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:189
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:439
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:190
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11925
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:917
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12703
TTrainController::TotLateExitMins
float TotLateExitMins
Definition: TrainUnit.h:773
TInterface::ManualLCDownAttentionWarning
bool ManualLCDownAttentionWarning
Displays the manual LC down warning graphic in the panel on the LHS of the railway when there are no ...
Definition: InterfaceUnit.h:1231
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2363
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:15094
IDInt
Definition: TrackUnit.h:511
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10645
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1095
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:21027
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1180
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:85
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:299
TUtilities
Definition: Utilities.h:36
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4328
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3269
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4718
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:515
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13422
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10027
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:146
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:814
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1129
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:182
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:555
TInterface::SigPrefNonConsecButton
TBitBtn * SigPrefNonConsecButton
Definition: InterfaceUnit.h:656
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:441
TInterface::GetTrainStatusFloat
AnsiString GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
used for floating window to display train status
Definition: InterfaceUnit.cpp:16775
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:190
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:279
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:321
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1183
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:9423
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:51
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:373
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:496
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:213
TTrainController::TotEarlyExitMins
float TotEarlyExitMins
Definition: TrainUnit.h:769
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5779
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:98
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:8731
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:154
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:887
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:404
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13013
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:774
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14034
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1690
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1683
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:17330
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:875
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:131
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:456
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2449
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7527
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12629
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1055
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:204
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12720
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:646
TInterface::RecoverClipboardMessageSent
bool RecoverClipboardMessageSent
indicates that the warning about pasting at top left in a new application has been given,...
Definition: InterfaceUnit.h:994
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:148
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:895
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1501
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:586
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4951
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:16121
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:931
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12784
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:620
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:896
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:77
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3195
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:57
TPrefDirElement::SetXLink
void SetXLink(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:364
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1053
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:117
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:88
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:461
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:639
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1390
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:655
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:653
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:9075
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:524
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:1002
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:925
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:878
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:952
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15221
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:595
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:778
TPrefDirElement::SetEXNumber
void SetEXNumber(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:376
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1193
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:15261
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:14073
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:763
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13336
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12972
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1295
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13111
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:152
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:552
Points
@ Points
Definition: TrackUnit.h:67
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:772
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:13593
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:14487
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:359
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:810
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:754
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:300
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:794
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1093
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:52
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3362
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1135
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13874
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1183
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1831
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13578
TInterface::SigPrefNonConsecButtonClick
void __fastcall SigPrefNonConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2256
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1054
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:367
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:458
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16637
TInterface::MMovePrefDirSelFlag
bool MMovePrefDirSelFlag
Definition: InterfaceUnit.h:977
TInterface::TwoLocationNamePanel
TPanel * TwoLocationNamePanel
Definition: InterfaceUnit.h:657
Continuation
@ Continuation
Definition: TrackUnit.h:67
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:251
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:143
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:740
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:71
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:843
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3648
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5844
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1117
TInterface::MMoveTrackSelFlag
bool MMoveTrackSelFlag
Definition: InterfaceUnit.h:976
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9555
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:600
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1064
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4099
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:315
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:761
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:788
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:432
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:546
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:9777
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:331
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:262
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11968
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:17922
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13686
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:179
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:490
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:435
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1674
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:52
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:885
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:962
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1052
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1152
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:305
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12836
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:20392
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12862
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:9454
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3265
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:466
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1518
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:438
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:345
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9436
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1150
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:347
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12776
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:622
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:542
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1180
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:8360
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:562
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:499
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3663
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3181
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:936
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:929
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:195
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:487
TTrainController::OnTimeExits
int OnTimeExits
Definition: TrainUnit.h:790
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:972
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:281
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:895
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:1032
TInterface::CancelSelectionFlag
bool CancelSelectionFlag
used in case pasting to avoid RecoverClipboard call when set
Definition: InterfaceUnit.h:946
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:464
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:53
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:354
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:988
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:5342
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12652
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:612
TTrackElement::TempTrackMarker01
bool TempTrackMarker01
Definition: TrackUnit.h:140
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:18925
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:780
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:631
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:527
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:889
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4581
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:570
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4917
TInterface::TwoLocationNameCheckBox
TCheckBox * TwoLocationNameCheckBox
Definition: InterfaceUnit.h:660
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1710
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8451
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:69
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:800
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3581
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:728
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4599
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:907
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:3121
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1180
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:720
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:212
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:19146
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:236
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:5090
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:915
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:518
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18892
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:432
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1054
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1841
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4566
Connection
@ Connection
Definition: TrackUnit.h:77
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4757
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3625
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:740
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1685
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:80
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:295
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3622
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:82
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16450
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1131
TInterface::MMoveCopyCutSelPickedUpFlag
bool MMoveCopyCutSelPickedUpFlag
Definition: InterfaceUnit.h:978
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18164
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:133
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13907
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13501
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:142
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:572
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6888
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:541
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4416
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1141
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:604
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:103
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:415
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:601
TPrefDirElement::SetTrackVectorPosition
void SetTrackVectorPosition(int TVPos)
Used in pasting pref dirs.
Definition: TrackUnit.h:341
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1200
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5652
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:414
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:895
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:302
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:124
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:252
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:335
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:767
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:782
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:117
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1072
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:9045
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:103
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1091
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:389
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:7020
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:747
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:14028
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17390
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13481
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1059
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:381
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7487
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3027
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:9060
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:536
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:133
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:331
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:860
TInterface::ManualLCDownImage
TImage * ManualLCDownImage
Definition: InterfaceUnit.h:268
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:652
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:820
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:642
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:982
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:336
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:862
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:927
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1174
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:293
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:311
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:173
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1062
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:765
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:203
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:8389
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:346
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:603
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:15054
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:261
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:519
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:302
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:17786
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:533
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1396
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:20763
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7612
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:895
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:667
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1056
TPrefDirElement::SetELinkPos
void SetELinkPos(int input)
Used in pasting pref dirs.
Definition: TrackUnit.h:358
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:283
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:99
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:615
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:244
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3961
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:606
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:20875
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1066
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11346
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:357
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:14523
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:571
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1058
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:784
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:59
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:442
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:485
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:101
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:479
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13403
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:754
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1133
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:64
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:213
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:411
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:804
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:776
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:12661
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:106
TTrainController::TTEditPanelVisible
bool TTEditPanelVisible
new at v2.6.0 so potential error message only shows in TTEdit mode
Definition: TrainUnit.h:752
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:5035
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:528
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:335
TInterface::TwoLocationNameLabel
TLabel * TwoLocationNameLabel
Definition: InterfaceUnit.h:658
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:440
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:636
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:864
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:78
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:142
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1069
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10677
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4188
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:285
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:806
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4457
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:895
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7350
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1936
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:418
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:725
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:454
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9523
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1052
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1125
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:20973
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1155
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:18806
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:577
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7145
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:410
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2054
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1378
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:996
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:863
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:990
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:771
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1137
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4482
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:651
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:188
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:782
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:635
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:481
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:474
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:131
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1060
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:98
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1302
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13327
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:15941
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9290
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:147
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:377
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1746
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:20808
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:272
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15642
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:103
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:644
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:808
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:150
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:118
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:623
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:369
TInterface::SelectPrefDir
TOnePrefDir * SelectPrefDir
Pref Dir elements in a selected region.
Definition: InterfaceUnit.h:1169
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:545
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:919
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:171
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2025
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:1010
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:754
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:629
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6169
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3683
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:51
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3525
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1950
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1911
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:15159
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:18341
TInterface::TwoLocationNameButtonClick
void __fastcall TwoLocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13970
TInterface::None
@ None
Definition: InterfaceUnit.h:901
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:593
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:12053
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:75
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10815
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:753
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1051
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:246
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:633
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:768
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:818
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1115
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:399
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:150
TPrefDirElement::SetCheckCount
void SetCheckCount(int ChkCnt)
Definition: TrackUnit.h:346
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:751
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:638
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1125
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:769
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:781
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:42
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:1006
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1038
TTextItem::TextString
AnsiString TextString
the text string
Definition: TextUnit.h:46
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:65
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:529
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:931
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:154
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:526
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:18574
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:885
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:643
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:125
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3408
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:107
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1103
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11280
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:584
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1061
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:186
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:187
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5390
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6787
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:443
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:309
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:574
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:18160
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18436
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1156
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1096
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11712
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:890
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:492
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:1089
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10844
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:134
TInterface::SigPrefConsecButton
TBitBtn * SigPrefConsecButton
Definition: InterfaceUnit.h:196
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:438
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:539
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:13441
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:688
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:532
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:38
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:754
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:436
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6070
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:159
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:68
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:19364
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:267
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:441
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10321
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:520
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:76
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:745
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:616
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:303
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:877
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1057
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:964
TInterface::TooShortMessageSentFlag
bool TooShortMessageSentFlag
indicates that the length of a location element might be too short (<50m), so it won't be given again
Definition: InterfaceUnit.h:1026
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:144
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3888
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2176
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1055
Signaller
@ Signaller
Definition: TrainUnit.h:58
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:527
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2992
TRailGraphics::smYellow
Graphics::TBitmap * smYellow
Definition: GraphicUnit.h:888
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1171
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:624
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10100
Bridge
@ Bridge
Definition: TrackUnit.h:67
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:958
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9615
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:544
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:14510
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:608
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:391
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:605
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:243
Buffers
@ Buffers
Definition: TrackUnit.h:67
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:895
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:209
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:841
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11304
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4790
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9775
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:517
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:901
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4394
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:455
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:554
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12810
TInterface::GetTrainIDOrContinuationPosition
bool GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &ContinuationPos)
Used in actions due panel to identify the train or continuation.
Definition: InterfaceUnit.cpp:5046